单元测试工具jmockit使用总结

Mockito和JMockit的对比:https://www.sibida.vip/article/126324

Mockito、JMockit、EasyMock、PowerMock、jMock、Unitils对比 :
https://blog.csdn.net/imi00/article/details/79306028
https://www.it1352.com/971527.html

简介

jmockit用来写ut,即单元测试。

中文官网:http://jmockit.cn/showChannel.htm?channel=1

关于单元测试ut、功能测试ft、系统测试st、验收测试uat:https://blog.csdn.net/cashcat2004/article/details/106393352

关于官网没有提到的,个人的经验:

  1. 提示期待和被期待的对象不同,但对比结果相同,如果不是必须同一个实例,可能是"null"在控制台打印的是null,null在控制台也打印的是null,可能是1L和1都显示1,使用BeyondCompare等对比工具发现不了。

  2. 控制台打印的被期待的逻辑是测试中写的,实际的逻辑是被测试的代码。

  3. @Mocked用在ut的变量里。

  4. Spring Test中提供了一些模拟的对象可以方便地使用。如:MockHttpServletRequest、MockHttpServletResponse、MockMultipartFile、MockFilterChain

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>5.1.14.RELEASE</version>
            </dependency>
    
  5. ut类中被注入的成员变量,也就是加了@Injectable的成员变量,是被jmockit自己实现,个人修改后,除非通过测试方法传参进去,否则不会生效。不会传参进去,又想自定义这个成员变量,只能自己写一个实现类,然后用jmockit提供的FieldReflection.setFieldValue(field, targetObject, value),它会通过反射将ut执行时的被测试类的成员变量改了,mocked后赋值、injectable后赋值、用mockup都不能解决问题。而且必须在测试方法执行前,不能写在Junit的@Before里,此时@Tested的变量还没有实例化;field可以被测试类.class.getDeclaredField(变量名)得到,targetObject就是@Tested的变量,value就是自己写的被测试类的成员变量的实现(接口实现或子类)。

  6. 被测试类里用到了自己,也就是注入了自己,此时,被测试方法内部用了自己,就会有NPE,也只能通过FieldReflection.setFieldValue解决。

  7. 被测试类里@Autowired方式注入或者构造方法的方法注入,都用@Injectable。

  8. coverage插件已经安装,打开工程后没有coverage窗口,coverage运行按钮是灰色的,重新打开工程可以解决。

  9. 在new Expectations里用jmockit的withInstanceLike方法,传入的参数不需要内容完全相同,也可以继续向下执行,可以结合将实例赋值来解决mapper执行insert后得到自增ID的场景。withInstanceOf只需传入参数类型就行。

  10. 将实例赋值,传递下去,实例对应的类不能是序列化的类:

    XXX xxx = new XXX();
    new Expectations(XXX.class){
      {
        new XXX();
        result = xxx;
      }
    };
    
  11. 解决TimeUtils:

    new Expectations(TimeUtils.class){
      {
        TimeUtils.currentTimeSecs();
        result = 1;
      }
    };
    
  12. System的currentTimeMillis是native方法,不能像TimeUtils一样解决,需用MockUp,MockUp对当前所在方法内涉及到的所有实例生效:

    new MockUp<System>() {
                @Mock
                public long currentTimeMillis() {
                    return 1;
                }
            };
    
  13. BufferedWriter、FileWriter等涉及到文件,也可以用MockUp解决,因为文件可能在服务器上,ut不依赖外部资源,所以不想报文件找不到,不想读写文件; i n i t 可 以 模 拟 构 造 方 法 , init可以模拟构造方法, initclinit可以模拟静态代码块http://jmockit.cn/showChannel.htm?channel=4:

    new MockUp<BufferedWriter>() {
                @Mock
                public void close() {
                }
    
                @Mock
                public void flush() {
    
                }
            };
    new MockUp<FileWriter>() {
                @Mock
                public void $init(File file, boolean append) {
                }
    
                @Mock
                public void close() {
                }
            };
    new MockUp<FileUtils>() {
                @Mock
                public void writeByteArrayToFile(File file, byte[] data) {
                }
            };
    
  14. 涉及到多线程的测试,模拟的方法被执行的次序需要固定,否则Expectation不能执行成功,所以需要将被测试类的多线程模拟成单线程执行:

    List<Runnable> runnableList = new ArrayList<>();
    new MockUp<ThreadPoolExecutor>(){
        @Mock
        public Future<?> submit(Runnable task){
            runnableList.add(task);
            // 2是任务的个数,将任务都存起来,存完后再依次执行,如果模拟时线程个数是外部传入的,可以直接传入1,多线程改单线程
            if(runnableList.size() == 2){
                runnableList.forEach(Runnable::run);
            }
    
            return null;
        }
    };
    
  15. 如果MockUp使用时,报mockit.internal.ClassFile$NotFoundException: Unable to find class file for,需调整MockUp的使用顺序,如:

    new MockUp<URLClassLoader>() {
        @Mock
        public InputStream getResourceAsStream(String name) {
            return null;
        }
    };
    new MockUp<FileUtils>(){
        @Mock
        public void writeByteArrayToFile(File file, byte[] data){
        }
    };
    // 会报:mockit.internal.ClassFile$NotFoundException: Unable to find class file for,交换一下顺序就能解决
    
  16. 一个类的静态成员变量实例化时抛出异常,想不抛出,可以用FieldReflection.setFieldValue,第二个参数传null就行。

  17. 被测试类的私有方法不被公开的调用,还想测试一下,可以用jmockit提供的MethodReflection.invoke反射执行。

其它:
18. IDEA的被测试类中,Mac是Command+Shift+T,Windows是Ctrl+Shift+T,然后回车,可以看到已有的测试类,也可以生成新的测试类:选择生成策略。
19. 在目录上可以右键Run … with coverage可以查看类、方法、行的覆盖率。
20. 运行ut后,就可以编辑下一个ut方法了,毕竟ut执行前jmockit需要执行一些代码。 开始运行后,编辑不会影响运行,可以节省ut编写时间,不要问我怎么知道的,当要覆盖37000行时,节省出来的时间很重要。
21. IDEA的Settings里搜Coverage,勾选Add to the active suits可以将目前的ut执行的Coverage合并到上一次执行的Coverage里,可以实时了解当前大目录的Coverage。
22. 可以用Statistic插件先看一下代码行集中在哪些目录,哪些类,可以更快地提升行覆盖率。
23. 被测试类的方法声明改测试类的同一个方法声明,IDEA里用正则替换:
public\s.\s(.)(.*)\s{0,1}{
public void $1() {
24. 测试类的方法统一test开头,下一个字母大写,IDEA里用正则替换:
@Test
public void ([a-su-z])
@Test
public void test\u$1
25. 如果被测试的类实例化时报错,可以在静态代码块中给被测试类的实例传入正确的参数。

补充:
jmockit教程_jmockit使用总结-MockUp重点介绍:https://blog.csdn.net/weixin_39606911/article/details/111798704
Java服务端单元测试指南:https://blog.csdn.net/ifidieyoung/article/details/83615394

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风铃峰顶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值