您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)怎么在Spring 元測試中實現(xiàn)一個mock功能,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關(guān)知識有一定的了解。
手動 mock
手動 mock 其實就是重新創(chuàng)建一個類繼承被 mock 的服務(wù)類,并重寫里面的方法。在單元測試中,利用依賴注入的方式使用 mock 的服務(wù)類替換原來的服務(wù)類。具體代碼示列如下:
/** * UserRepository * * @author star */ @Repository public class UserRepository { /** * 模擬從數(shù)據(jù)庫中獲取用戶信息,實際開發(fā)中需要連接真實的數(shù)據(jù)庫 */ public User getUser(String name) { User user = new User(); user.setName("testing"); user.setEmail("testing@outlook.com"); return user; } } /** * MockUserRepository * * @author star */ public class MockUserRepository extends UserRepository { /** * 模擬從數(shù)據(jù)庫中獲取用戶信息 */ @Override public User getUser(String name) { User user = new User(); user.setName("mock-test-name"); user.setEmail("mock-test-email"); return user; } } // 進行單元測試 @RunWith(SpringRunner.class) @SpringBootTest public class UserServiceManualTest { @Autowired private UserService userService; @Test public void testGetUser_Manual() { // 將 MockUserRepository 注入到 UserService 中 userService.setUserRepository(new MockUserRepository()); User user = userService.getUser("mock-test-name"); Assert.assertEquals("mock-test-name", user.getName()); Assert.assertEquals("mock-test-email", user.getEmail()); } }
從上面的代碼中,我們可以看到手動 mock 需要編寫大量的額外代碼,同時被測試類也需要提供依賴注入的入口(setter 方法等)。如果被 mock 的類修改了函數(shù)名稱或者功能,mock 類也要跟著修改,增加了維護成本。
為了提高效率,減少維護成本,我們推薦使用單元測是框架進行 mock。
這里我們主要介紹 Mokito.mock()、@Mock、@MockBean 這三種方式的 mock。
Mocito.mock()
Mocito.mock() 方法允許我們創(chuàng)建類或接口的 mock 對象。然后,我們可以使用 mock 對象指定其方法的返回值,并驗證其方法是否被調(diào)用。代碼示列如下:
@Test public void testGetUser_MockMethod() { // 模擬 UserRepository,測試時不直接操作數(shù)據(jù)庫 UserRepository mockUserRepository = Mockito.mock(UserRepository.class); // 將 mockUserRepository 注入到 UserService 類中 userService.setUserRepository(mockUserRepository); User mockUser = mockUser(); Mockito.when(mockUserRepository.getUser(mockUser.getName())) .thenReturn(mockUser); User user = userService.getUser(mockUser.getName()); Assert.assertEquals(mockUser.getName(), user.getName()); Assert.assertEquals(mockUser.getEmail(), user.getEmail()); // 驗證 mockUserRepository.getUser() 方法是否執(zhí)行 Mockito.verify(mockUserRepository).getUser(mockUser.getName()); }
@Mock
@Mock 是 Mockito.mock() 方法的簡寫。同樣,我們應(yīng)該只在測試類中使用它。與 Mockito.mock() 方法不同的是,我們需要在測試期間啟用 Mockito 注解才能使用 @Mock 注解。
我們可以調(diào)用 MockitoAnnotations.initMocks(this) 靜態(tài)方法來啟用 Mockito 注解。為了避免測試之間的副作用,建議在每次測試執(zhí)行之前先進行以下操作:
@Before public void setup() { // 啟用 Mockito 注解 MockitoAnnotations.initMocks(this); }
我們還可以使用另一種方法來啟用 Mockito 注解。通過在 @RunWith() 指定 MockitoJUnitRunner 來運行測試:
@RunWith(MockitoJUnitRunner.class) public class UserServiceMockTest { }
下面我們來看看如何使用 @Mock 進行服務(wù) mock。代碼示列如下:
@RunWith(SpringRunner.class) @SpringBootTest public class UserServiceMockTest { @Mock private UserRepository userRepository; @Autowired @InjectMocks private UserService userService; private User mockUser() { User user = new User(); user.setName("mock-test-name"); user.setEmail("mock-test-email"); return user; } @Before public void setup() { // 啟用 Mockito 注解 MockitoAnnotations.initMocks(this); } @Test public void testGetUser_MockAnnotation() { User mockUser = mockUser(); Mockito.when(userRepository.getUser(mockUser.getName())) .thenReturn(mockUser); User user = userService.getUser(mockUser.getName()); Assert.assertEquals(mockUser.getName(), user.getName()); Assert.assertEquals(mockUser.getEmail(), user.getEmail()); // 驗證 mockUserRepository.getUser() 方法是否執(zhí)行 Mockito.verify(userRepository).getUser(mockUser.getName()); } }
Mockito 的 @InjectMocks 注解作用是將 @Mock 所修飾的 mock 對象注入到指定類中替換原有的對象。
@MockBean
@MockBean 是 Spring Boot 中的注解。我們可以使用 @MockBean 將 mock 對象添加到 Spring 應(yīng)用程序上下文中。該 mock 對象將替換應(yīng)用程序上下文中任何現(xiàn)有的相同類型的 bean。如果應(yīng)用程序上下文中沒有相同類型的 bean,它將使用 mock 的對象作為 bean 添加到上下文中。
@MockBean 在需要 mock 特定 bean(例如外部服務(wù))的集成測試中很有用。
要使用 @MockBean 注解,我們必須在 @RunWith() 中指定 SpringRunner 來運行測試。代碼示列如下:
@RunWith(SpringRunner.class) @SpringBootTest public class UserServiceMockBeanTest { @MockBean private UserRepository userRepository; private User mockUser() { User user = new User(); user.setName("mock-test-name"); user.setEmail("mock-test-email"); return user; } @Test public void testGetUser_MockBean() { User mockUser = mockUser(); // 模擬 UserRepository Mockito.when(userRepository.getUser(mockUser.getName())) .thenReturn(mockUser); // 驗證結(jié)果 User user = userRepository.getUser(mockUser.getName()); Assert.assertEquals(mockUser.getName(), user.getName()); Assert.assertEquals(mockUser.getEmail(), user.getEmail()); Mockito.verify(userRepository).getUser(mockUser.getName()); } }
這里需要注意的是,Spring test 默認(rèn)會重用 bean。如果 A 測試使用 mock 對象進行測試,而 B 測試使用原有的相同類型對象進行測試,B 測試在 A 測試之后運行,那么 B 測試拿到的對象是 mock 的對象。一般這種情況是不期望的,所以需要用 @DirtiesContext 修飾上面的測試避免這個問題。
關(guān)于怎么在Spring 元測試中實現(xiàn)一個mock功能就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。