您好,登錄后才能下訂單哦!
小編給大家分享一下Java單元測試Powermockito和Mockito使用的示例分析,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>2.8.9</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>1.7.4</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>1.7.4</version> <scope>test</scope> </dependency>
Mockito、EasyMock、JMock等比較流行Mock框架有個共同的缺點,都不能mock靜態、final、私有方法等,而PowerMock可以完美解決以上框架的不足,接下來讓我們看看無所不能的PowerMock是如何解決上述問題,我們先從一個實例來看,下面的代碼是需要單測的類,被測類中既有對Spring Bean的調用,同時又包含對Redis的靜態讀取,另外還有getInstance()單例類的使用,現在,我們一一來mock上述的外部類。
被單測類(主要測試queryStudentScoreByKeyword方法)
@Component public class StudentService { @Resource private StudentDao studentDao; public List<StudentBo> queryStudentScoreByKeyword(String name) { System.out.println("invoke StudentService.queryStudentScoreByKeyword ..."); List<StudentBo> cacheList = RedisUtils.getArray(name, StudentBo.class); if (CollectionUtils.isNotEmpty(cacheList)) { return cacheList; } String keyword = processKeyword(name); List<Student> students = studentDao.queryStudentByKeyWord(keyword); List<Integer> ids = students.stream().map(Student::getId).collect(Collectors.toList()); List<Person> personList = SchoolManageProxy.getInstance().queryPerson(ids); List<StudentBo> studentBos = CommonUtils.toBo(personList, students); // 高亮結果 highlightResult(studentBos, name); // 緩存到Redis RedisUtils.setArray(name, studentBos, 10 * 60); return studentBos; } private String processKeyword(String name) { System.out.println("invoke StudentService.processKeyword ..."); String newName = name; // do somethings return newName; } private void highlightResult(List<StudentBo> result, String name) { System.out.println("invoke StudentService.highlightResult ..."); // do keyword highlight } }
單測類
@RunWith(PowerMockRunner.class) @PrepareForTest({SchoolManageProxy.class, RedisUtils.class, StudentService.class}) // @PowerMockIgnore({"javax.management.*", "javax.net.ssl.*"}) @SuppressStaticInitializationFor({"cn.ganzhiqiang.ares.unittest.SchoolManageProxy"}) public class StudentServiceTest { @Mock private StudentDao mockStudentDao; @InjectMocks private StudentService studentServiceUnderTest; @Before public void setUp() { initMocks(this); } @Test public void testQueryStudentScoreByKeyword() throws Exception { studentServiceUnderTest = PowerMockito.spy(studentServiceUnderTest); PowerMockito.mockStatic(RedisUtils.class); PowerMockito.mockStatic(SchoolManageProxy.class); // mock單例調用 SchoolManageProxy mockSchoolManageProxy = PowerMockito.mock(SchoolManageProxy.class); PowerMockito.when(SchoolManageProxy.getInstance()).thenReturn(mockSchoolManageProxy); when(mockSchoolManageProxy.queryPerson(anyList())).thenReturn(Collections.emptyList()); // mock掉對Redis的靜態調用 PowerMockito.when(RedisUtils.getArray(eq("tom"), eq(StudentBo.class))).thenReturn(Collections.emptyList()); // 顯示的mock掉靜態的void的方法(可以不mock) PowerMockito.doNothing().when(RedisUtils.class, "setArray", anyString(), anyList(), anyInt()); // mock私有方法processKeyword PowerMockito.doReturn("tom").when(studentServiceUnderTest, "processKeyword", anyString()); // 跳過私有方法highlightResult的執行 PowerMockito.suppress(PowerMockito.method(StudentService.class, "highlightResult")); // 使用Mockito來mock服務的調用 when(mockStudentDao.queryStudentByKeyWord(anyString())).thenReturn(Collections.emptyList()); // Run the test final List<StudentBo> result = studentServiceUnderTest.queryStudentScoreByKeyword("tom"); } }
首選我們先用Mockito來mock對Spring Bean的調用,Mockito.mock可以mock一個實例,我們這里選用@Mock注解,效果是一樣的。
// 使用Mockito來mock服務的調用 when(mockStudentDao.queryStudentByKeyWord(anyString())).thenReturn(Collections.emptyList());
接下來我們使用PowerMock來mock對靜態方法的調用,注意需要將RedisUtils類,加入@PrepareForTest注解中,我們既mock了getArray方法,也mock了setArray方法,其實setArray不需要mock這里顯式的mock了
PowerMockito.mockStatic(RedisUtils.class); // mock掉對Redis的靜態調用 PowerMockito.when(RedisUtils.getArray(eq("tom"), eq(StudentBo.class))).thenReturn(Collections.emptyList()); // 顯式的mock掉靜態的void的方法(可以不mock) PowerMockito.doNothing().when(RedisUtils.class, "setArray", anyString(), anyList(), anyInt());
mock單例類相對來說復雜一點,邏輯上先用Powermock mock出單例類,然后再給單例類的getInstance方法打樁,返回之前mock,再對mock類實際調用的方法打樁即可,代碼如下
PowerMockito.mockStatic(SchoolManageProxy.class); // Powermock mock出單例類 SchoolManageProxy mockSchoolManageProxy = PowerMockito.mock(SchoolManageProxy.class); // 給單例類的getInstance方法打樁 PowerMockito.when(SchoolManageProxy.getInstance()).thenReturn(mockSchoolManageProxy); // 對mock類queryPerson的方法打樁 when(mockSchoolManageProxy.queryPerson(anyList())).thenReturn(Collections.emptyList());
可以看到queryStudentScoreByKeyword方法調用了該類的私有方法processKeyword,如果該方法耗時過長,使用powermock也可以mock該私有方法,需要注意的studentServiceUnderTest需要用spy()來mock
// mock 實例 // spy的標準是:如果不打樁,默認執行真實的方法,如果打樁則返回樁實現。 studentServiceUnderTest = PowerMockito.spy(studentServiceUnderTest); // mock私有方法processKeyword // doReturn(...) when(...)不做真實調用,但是when(...) thenReturn(...)還是會真實調用原方法,只是返回了指定的結果 PowerMockito.doReturn("tom").when(studentServiceUnderTest, "processKeyword", anyString());
使用PowerMock也可以跳過私有方法的執行
// 跳過私有方法highlightResult的執行 PowerMockito.suppress(PowerMockito.method(StudentService.class, "highlightResult"));
看完了這篇文章,相信你對“Java單元測試Powermockito和Mockito使用的示例分析”有了一定的了解,如果想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。