千家信息网

Java单元测试Powermockito和Mockito使用的示例分析

发表于:2024-10-04 作者:千家信息网编辑
千家信息网最后更新 2024年10月04日,小编给大家分享一下Java单元测试Powermockito和Mockito使用的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!依赖引入 org.mockito m
千家信息网最后更新 2024年10月04日Java单元测试Powermockito和Mockito使用的示例分析

小编给大家分享一下Java单元测试Powermockito和Mockito使用的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

    依赖引入

        org.mockito    mockito-core    2.8.9    test    org.powermock    powermock-module-junit4    1.7.4    test    org.powermock    powermock-api-mockito2    1.7.4    test

    PowerMockito的使用

    Mockito、EasyMock、JMock等比较流行Mock框架有个共同的缺点,都不能mock静态、final、私有方法等,而PowerMock可以完美解决以上框架的不足,接下来让我们看看无所不能的PowerMock是如何解决上述问题,我们先从一个实例来看,下面的代码是需要单测的类,被测类中既有对Spring Bean的调用,同时又包含对Redis的静态读取,另外还有getInstance()单例类的使用,现在,我们一一来mock上述的外部类。

    被单测类(主要测试queryStudentScoreByKeyword方法)

    @Componentpublic class StudentService {    @Resource    private StudentDao studentDao;    public List queryStudentScoreByKeyword(String name) {        System.out.println("invoke StudentService.queryStudentScoreByKeyword ...");        List cacheList = RedisUtils.getArray(name, StudentBo.class);        if (CollectionUtils.isNotEmpty(cacheList)) {            return cacheList;        }        String keyword = processKeyword(name);        List students = studentDao.queryStudentByKeyWord(keyword);        List ids = students.stream().map(Student::getId).collect(Collectors.toList());        List personList = SchoolManageProxy.getInstance().queryPerson(ids);        List 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 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 result = studentServiceUnderTest.queryStudentScoreByKeyword("tom");    }}

    使用mockito来mock实例

    首选我们先用Mockito来mock对Spring Bean的调用,Mockito.mock可以mock一个实例,我们这里选用@Mock注解,效果是一样的。

    // 使用Mockito来mock服务的调用 when(mockStudentDao.queryStudentByKeyWord(anyString())).thenReturn(Collections.emptyList());

    mock对Redis的静态调用

    接下来我们使用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单例类

    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());

    mock私有方法

    可以看到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跳过方法执行

    使用PowerMock也可以跳过私有方法的执行

    // 跳过私有方法highlightResult的执行PowerMockito.suppress(PowerMockito.method(StudentService.class, "highlightResult"));

    看完了这篇文章,相信你对"Java单元测试Powermockito和Mockito使用的示例分析"有了一定的了解,如果想了解更多相关知识,欢迎关注行业资讯频道,感谢各位的阅读!

    0