温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2021-09-08 13:34:48 来源:亿速云 阅读:196 作者:小新 栏目:开发技术

小编给大家分享一下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>

    PowerMockito的使用

    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实例

    首选我们先用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使用的示例分析”有了一定的了解,如果想了解更多相关知识,欢迎关注亿速云行业资讯频道,感谢各位的阅读!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI