日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

Mockito 避坑指南 - 常見錯誤的預防與處理

來源: 責編: 時間:2023-11-01 17:04:47 289觀看
導讀介紹Mockito 是一個流行的用于測試 Java 應用程序的框架。它提供了一種強大且易于使用的方式來模擬依賴關系和編寫單元測試。然而,剛接觸 Mockito 的開發(fā)人員可能會犯一些錯誤,從而導致測試不可靠,甚至導致應用程序出現

介紹

sD928資訊網——每日最新資訊28at.com

Mockito 是一個流行的用于測試 Java 應用程序的框架。它提供了一種強大且易于使用的方式來模擬依賴關系和編寫單元測試。然而,剛接觸 Mockito 的開發(fā)人員可能會犯一些錯誤,從而導致測試不可靠,甚至導致應用程序出現意外行為。在本文中,我們將討論開發(fā)人員在 Spring Boot 應用程序中使用 Mockito 框架時犯的常見錯誤,以及代碼示例和解釋。sD928資訊網——每日最新資訊28at.com

1.濫用@Mock和@InjectMocks注釋

開發(fā)人員在使用 Mockito 時最常見的錯誤之一是濫用@Mock和@InjectMocks注釋。@Mock注解用于為特定類創(chuàng)建模擬對象,而@InjectMocks注解用于將模擬對象注入到被測試的類中。需要注意的是,@InjectMocks 只能與類一起使用,不能與接口一起使用。sD928資訊網——每日最新資訊28at.com

例子:sD928資訊網——每日最新資訊28at.com

@RunWith(MockitoJUnitRunner.class)public class MyServiceTest {        @Mock    private MyRepository myRepository;        @InjectMocks    private MyService myService;        // test methods    }

2.不重置Mock對象

Mockito 可創(chuàng)建在多個測試中重用的Mock對象。如果在測試之間未重置Mock對象,則可能會導致意外行為和不可靠的測試。Mockito 提供了一個名為Mockito.reset()的方法,可用于重置所有Mock對象。sD928資訊網——每日最新資訊28at.com

例子:sD928資訊網——每日最新資訊28at.com

@Beforepublic void setUp() {    MockitoAnnotations.initMocks(this);}@Testpublic void test1() {    Mockito.when(myRepository.findById(1)).thenReturn(Optional.of(new MyObject()));    // test code}@Testpublic void test2() {    Mockito.when(myRepository.findById(2)).thenReturn(Optional.of(new MyObject()));    // test code}@Afterpublic void tearDown() {    Mockito.reset(myRepository);}

3.對Mock對象使用錯誤的范圍

Mockito 默認創(chuàng)建范圍為類級別。這意味著同一個Mock對象將用于類中的所有測試方法。但是,如果模擬對象需要為每個測試方法具有不同的狀態(tài)或行為,則應使用方法級別的范圍來創(chuàng)建。要創(chuàng)建具有正確范圍的Mock對象,我們可以使用Spring Boot 提供的@MockBean注解。sD928資訊網——每日最新資訊28at.com

@MockBean使用示例:sD928資訊網——每日最新資訊28at.com

@RunWith(SpringRunner.class)@WebMvcTest(UserController.class)public class UserControllerTest {    @Autowired    private MockMvc mockMvc;    @MockBean    private UserService userService;    @MockBean    private UserRepository userRepository;    @Test    public void testGetUserById() throws Exception {        // arrange        Long userId = 1L;        User user = new User();        user.setId(userId);        user.setName("John Doe");        Mockito.when(userService.getUserById(userId)).thenReturn(user);        // act        MvcResult result = mockMvc.perform(get("/users/{id}", userId))                .andExpect(status().isOk())                .andReturn();        // assert        String response = result.getResponse().getContentAsString();        assertThat(response).isEqualTo("{/"id/":1,/"name/":/"John Doe/"}");        Mockito.verify(userService, times(1)).getUserById(userId);    }    @Test    public void testAddUser() throws Exception {        // arrange        User user = new User();        user.setName("Jane Doe");        Mockito.when(userService.addUser(user)).thenReturn(user);        // act        MvcResult result = mockMvc.perform(post("/users")                .contentType(MediaType.APPLICATION_JSON)                .content("{/"name/":/"Jane Doe/"}"))                .andExpect(status().isOk())                .andReturn();        // assert        String response = result.getResponse().getContentAsString();        assertThat(response).isEqualTo("{/"id/":null,/"name/":/"Jane Doe/"}");        Mockito.verify(userService, times(1)).addUser(user);    }}

在這個例子中,我們使用@WebMvcTest注解來測試UserController類,并注入MockMvc對象來模擬HTTP請求。我們還使用@MockBean注釋為UserService和UserRepository類創(chuàng)建模擬對象。sD928資訊網——每日最新資訊28at.com

注意,這里不需要在測試之間重置Mock對象,因為@MockBean注解會為每個測試方法創(chuàng)建Mock對象的新實例。sD928資訊網——每日最新資訊28at.com

4.不驗證Mock對象

Mockito 提供了 Mockito.verify()的方法,可用于驗證是否使用特定參數調用了Mock對象。如果Mock對象未經驗證,可能會導致不可靠的測試和意外的行為。sD928資訊網——每日最新資訊28at.com

Mockito.verify()使用示例:sD928資訊網——每日最新資訊28at.com

@RunWith(MockitoJUnitRunner.class)public class UserServiceTest {    @Mock    private UserRepository userRepository;    @InjectMocks    private UserService userService;    @Test    public void testGetUserById() {        // arrange        Long userId = 1L;        User user = new User();        user.setId(userId);        user.setName("John Doe");        Mockito.when(userRepository.findById(userId)).thenReturn(Optional.of(user));        // act        User result = userService.getUserById(userId);        // assert        assertThat(result).isEqualTo(user);        Mockito.verify(userRepository, times(1)).findById(userId);    }    @Test    public void testGetUserByIdNotFound() {        // arrange        Long userId = 1L;        Mockito.when(userRepository.findById(userId)).thenReturn(Optional.empty());        // act        UserNotFoundException exception = assertThrows(UserNotFoundException.class, () -> {            userService.getUserById(userId);        });        // assert        assertThat(exception.getMessage()).isEqualTo("User not found with ID: " + userId);        Mockito.verify(userRepository, times(1)).findById(userId);    }}

請注意,我們使用該Mockito.verify()方法來驗證兩個測試方法是否使用正確的 ID 并僅調用了該類的findById()方法一次。使用times(1)參數來指定該方法應該被調用一次,并傳入正確的 ID 作為參數。如果未使用正確的 ID 調用該方法,或者多次調用該方法,則測試將失敗。sD928資訊網——每日最新資訊28at.com

5.不指定Mock對象的行為

Mockito 默認創(chuàng)建Mock對象,默認行為是“不執(zhí)行任何操作”。這意味著,如果在Mock對象上調用方法并且未指定任何行為,則該方法將僅返回 null 或其返回類型的默認值。指定Mock對象的行為來確保它們在測試中按預期運行非常重要。下面是使用Mockito.when()方法指定Mock對象的行為的示例:sD928資訊網——每日最新資訊28at.com

@RunWith(MockitoJUnitRunner.class)public class UserServiceTest {    @Mock    private UserRepository userRepository;    @InjectMocks    private UserService userService;    @Test    public void testGetAllUsers() {        // arrange        List<User> users = Arrays.asList(                new User(1L, "John Doe"),                new User(2L, "Jane Doe")        );        Mockito.when(userRepository.findAll()).thenReturn(users);        // act        List<User> result = userService.getAllUsers();        // assert        assertThat(result).isEqualTo(users);    }    @Test    public void testGetAllUsersEmpty() {        // arrange        List<User> users = Collections.emptyList();        Mockito.when(userRepository.findAll()).thenReturn(users);        // act        List<User> result = userService.getAllUsers();        // assert        assertThat(result).isEqualTo(users);    }}

6.使用錯誤的方法驗證模擬對象

Mockito 提供了幾種方法來驗證是否使用特定參數調用了Mock對象,例如Mockito.verify()、Mockito.verifyZeroInteractions () 和Mockito.verifyNoMoreInteractions () 。使用正確的方法進行所需的驗證非常重要,因為使用錯誤的方法可能會導致不可靠的測試和意外的行為。Mockito.verify()方法使用示例:sD928資訊網——每日最新資訊28at.com

@RunWith(MockitoJUnitRunner.class)public class UserServiceTest {    @Mock    private UserRepository userRepository;    @InjectMocks    private UserService userService;    @Test    public void testGetAllUsers() {        // arrange        List<User> users = Arrays.asList(                new User(1L, "John Doe"),                new User(2L, "Jane Doe")        );        Mockito.when(userRepository.findAll()).thenReturn(users);        // act        List<User> result = userService.getAllUsers();        // assert        assertThat(result).isEqualTo(users);        Mockito.verify(userRepository).findAll();        Mockito.verifyNoMoreInteractions(userRepository);    }    @Test    public void testEmptyUserList() {        // arrange        List<User> users = Collections.emptyList();        Mockito.when(userRepository.findAll()).thenReturn(users);        // act        List<User> result = userService.getAllUsers();        // assert        assertThat(result).isEqualTo(users);        Mockito.verify(userRepository).findAll();        Mockito.verifyNoMoreInteractions(userRepository);        Mockito.verifyZeroInteractions(userRepository);    }}

在第二個測試用例中,我們使用Mockito.verifyZeroInteractions()方法來驗證測試期間沒有與Mock對象發(fā)生交互。這確保只測試我們想要測試的行為,并且代碼中不會發(fā)生意外的交互。sD928資訊網——每日最新資訊28at.com

7.不處理異常

以下是使用 Mockito 時如何處理異常的示例:sD928資訊網——每日最新資訊28at.com

@RunWith(MockitoJUnitRunner.class)public class UserServiceTest {    @Mock    private UserRepository userRepository;    @InjectMocks    private UserService userService;    @Test    public void testGetUserById() {        // arrange        Long userId = 1L;        User user = new User();        user.setId(userId);        user.setName("John Doe");        Mockito.when(userRepository.findById(userId)).thenReturn(Optional.of(user));        // act        User result = userService.getUserById(userId);        // assert        assertThat(result).isEqualTo(user);    }    @Test    public void testGetUserByIdNotFound() {        // arrange        Long userId = 1L;        Mockito.when(userRepository.findById(userId)).thenReturn(Optional.empty());        // act and assert        UserNotFoundException exception = assertThrows(UserNotFoundException.class, () -> {            userService.getUserById(userId);        });        assertThat(exception.getMessage()).isEqualTo("User not found with ID: " + userId);    }}

在testGetUserByIdNotFound()方法中,我們Mock UserRepository 類的 findById() 方法以返回一個空的可選值。然后,我們使用特定 ID 調用UserService類的getUserById()方法,并且期望該方法拋出UserNotFoundException. 然后使用assertThrows()方法來驗證是否拋出了正確的異常,并且我們還使用getMessage()異常的方法來驗證是否返回了正確的消息。sD928資訊網——每日最新資訊28at.com

8.不使用正確的匹配器

以下是使用 Mockito 時如何使用正確匹配器的示例:sD928資訊網——每日最新資訊28at.com

@RunWith(MockitoJUnitRunner.class)public class UserServiceTest {    @Mock    private UserRepository userRepository;    @InjectMocks    private UserService userService;    @Test    public void testAddUser() {        // arrange        User user = new User();        user.setName("John Doe");        user.setAge(30);        // act        userService.addUser(user);        // assert        ArgumentCaptor<User> captor = ArgumentCaptor.forClass(User.class);        Mockito.verify(userRepository).save(captor.capture());        assertThat(captor.getValue().getName()).isEqualTo("John Doe");        assertThat(captor.getValue().getAge()).isEqualTo(30);    }}

使用ArgumentCaptor類來捕獲傳遞給UserRepository類的save()方法的參數值。我們還使用Mockito.eq()方法來指定方法調用的參數值,使用user.getName()和user.getAge()方法來獲取正確的值。這有助于確保向方法傳遞正確的參數,并避免在測試中出現意外的行為。sD928資訊網——每日最新資訊28at.com

下面是另一個示例:sD928資訊網——每日最新資訊28at.com

@RunWith(MockitoJUnitRunner.class)public class UserServiceTest {    @Mock    private UserRepository userRepository;    @InjectMocks    private UserService userService;    @Test    public void testDeleteUserById() {        // arrange        Long userId = 1L;        // act        userService.deleteUserById(userId);        // assert        Mockito.verify(userRepository, Mockito.times(1)).deleteById(Mockito.eq(userId));    }}

使用Mockito.eq()方法來指定deleteById()方法調用的參數值。這確保了正確的ID被傳遞給該方法,并避免了測試中的意外行為。sD928資訊網——每日最新資訊28at.com

9.沒有對Mock對象使用正確的注解

以下是使用@MockBean 和 @RunWith 注解示例:sD928資訊網——每日最新資訊28at.com

@RunWith(SpringRunner.class)@SpringBootTestpublic class UserServiceTest {    @Autowired    private UserService userService;    @MockBean    private UserRepository userRepository;    @Test    public void testGetAllUsers() {        // arrange        List<User> users = Arrays.asList(                new User(1L, "John Doe"),                new User(2L, "Jane Doe")        );        Mockito.when(userRepository.findAll()).thenReturn(users);        // act        List<User> result = userService.getAllUsers();        // assert        assertThat(result).isEqualTo(users);    }}

使用@RunWith和@SpringBootTest注解來配置單元測試的Spring測試框架。通過使用這些注解,我們可以確保應用程序上下文被加載并且依賴項被正確地注入。sD928資訊網——每日最新資訊28at.com

10.未使用正確的測試配置

我們希望使用正確的配置,以確保正確加載應用程序上下文并按預期注入依賴項。以下是使用@ContextConfiguration 的示例:sD928資訊網——每日最新資訊28at.com

@RunWith(MockitoJUnitRunner.class)@ContextConfiguration(classes = {UserService.class, UserRepository.class})public class UserServiceTest {    @Mock    private UserRepository userRepository;    @InjectMocks    private UserService userService;    @Test    public void testGetAllUsers() {        // arrange        List<User> users = Arrays.asList(                new User(1L, "John Doe"),                new User(2L, "Jane Doe")        );        Mockito.when(userRepository.findAll()).thenReturn(users);        // act        List<User> result = userService.getAllUsers();        // assert        assertThat(result).isEqualTo(users);    }}

使用@ContextConfiguration注解來指定測試的配置。我們將一個類數組傳遞給它,其中包括UserService和UserRepository類,這樣可以確保它們被加載到應用程序上下文中。sD928資訊網——每日最新資訊28at.com

11.沒有使用正確的方法來創(chuàng)建Mock對象

使用正確的方法來創(chuàng)建Mock對象,以確保依賴項的行為是可控的并且測試是可靠的。以下是使用Mockito.mock()的示例:sD928資訊網——每日最新資訊28at.com

@RunWith(MockitoJUnitRunner.class)public class UserServiceTest {    private UserService userService;    private UserRepository userRepository;    @Before    public void setUp() {        userRepository = Mockito.mock(UserRepository.class);        userService = new UserService(userRepository);    }    @Test    public void testGetAllUsers() {        // arrange        List<User> users = Arrays.asList(                new User(1L, "John Doe"),                new User(2L, "Jane Doe")        );        Mockito.when(userRepository.findAll()).thenReturn(users);        // act        List<User> result = userService.getAllUsers();        // assert        assertThat(result).isEqualTo(users);    }}

使用了Mockito.when()方法來指定Mock對象的行為,即當findAll()方法被調用時,返回一個User對象的列表。sD928資訊網——每日最新資訊28at.com

12.沒有使用正確的方法來存根Mock對象

使用正確的方法來存根Mock對象,以確保依賴項的行為可以控制并且測試是可靠的。以下是使用when().thenReturn()的示例:sD928資訊網——每日最新資訊28at.com

@RunWith(MockitoJUnitRunner.class)public class UserServiceTest {    @Mock    private UserRepository userRepository;    @InjectMocks    private UserService userService;    @Test    public void testGetAllUsers() {        // arrange        List<User> users = Arrays.asList(                new User(1L, "John Doe"),                new User(2L, "Jane Doe")        );        Mockito.when(userRepository.findAll()).thenReturn(users);        // act        List<User> result = userService.getAllUsers();        // assert        assertThat(result).isEqualTo(users);    }}

通過使用Mockito提供的when().thenReturn()方法,我們可以指定模擬對象的行為并確保在測試中控制依賴項。sD928資訊網——每日最新資訊28at.com

13.沒有使用正確的方法來驗證Mock對象的交互

Mockito 提供了幾種驗證 Mock對象交互的方法,例如Mockito.verify()、Mockito.verifyZeroInteractions()和Mockito.verifyNoMoreInteractions()。使用正確的方法來實現所需的行為非常重要,因為使用錯誤的方法可能會導致不可靠的測試和意外的行為。sD928資訊網——每日最新資訊28at.com

@Testpublic void test() {    MyObject myObject = new MyObject();    myObject.setName("Name");    Mockito.when(myRepository.findById(1)).thenReturn(Optional.of(myObject));        MyObject result = myService.findById(1);        Mockito.verify(myRepository).findById(1);    Mockito.verifyNoMoreInteractions(myRepository);    Assert.assertEquals("Name", result.getName());}

14.沒有使用正確的方法來驗證Mock對象的交互順序

Mockito 提供了一個名為Mockito.inOrder()的方法,可用于驗證與模擬對象交互的順序。在驗證交互順序時使用此方法非常重要。sD928資訊網——每日最新資訊28at.com

@Testpublic void test() {    MyObject myObject1 = new MyObject();    myObject1.setName("Name 1");    MyObject myObject2 = new MyObject();    myObject2.setName("Name 2");    InOrder inOrder = Mockito.inOrder(myRepository);        Mockito.when(myRepository.findById(1)).thenReturn(Optional.of(myObject1));    Mockito.when(myRepository.findById(2)).thenReturn(Optional.of(myObject2));        MyObject result1 = myService.findById(1);    MyObject result2 = myService.findById(2);        inOrder.verify(myRepository).findById(1);    inOrder.verify(myRepository).findById(2);    Assert.assertEquals("Name 1", result1.getName());    Assert.assertEquals("Name 2", result2.getName());}

結論

Mockito 是一個強大的測試框架。但是,剛接觸 Mockito 的開發(fā)人員可能會犯錯誤,從而導致應用程序中的測試不可靠和出現意外行為。sD928資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-16372-0.htmlMockito 避坑指南 - 常見錯誤的預防與處理

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 一文了解負載均衡器、反向代理、API 網關區(qū)別

下一篇: Spring Boot 多個環(huán)境的配置方式

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 金昌市| 邮箱| 武邑县| 长阳| 乌拉特前旗| 汪清县| 阿鲁科尔沁旗| 岳阳市| 合川市| 二手房| 马龙县| 洛浦县| 德令哈市| 龙里县| 连城县| 卢湾区| 都江堰市| 平阴县| 海宁市| 阳原县| 岐山县| 镇原县| 巩义市| 临高县| 武邑县| 云林县| 临洮县| 柘荣县| 乐清市| 唐海县| 大连市| 通河县| 民和| 绥棱县| 宜兰市| 长沙县| 阳谷县| 长阳| 奉化市| 驻马店市| 宝鸡市|