InjectMocks使用@InjectMocks注解 , 可以将mock或spy的对象自动注入要测试的对象 。这在Spring等使用自动注入的框架里用得非常广泛 。
@MockMap<String, String> wordMap; @InjectMocksMyDictionary dic = new MyDictionary();// 类定义:class MyDictionary { Map<String, String> wordMap; public MyDictionary() { wordMap = new HashMap<String, String>(); } public void add(final String word, final String meaning) { wordMap.put(word, meaning); } public String getMeaning(final String word) { return wordMap.get(word); }}
打桩所谓打桩 , 其实就是mock的一个过程 。我们给定期望的输入和输入 , mock的对象就能够如我们期望的那样工作 。
打桩有两种写法 , 一种是传统的写法 , 一种是BDD **Behavior-Driven Development (行为驱动开发)**的写法 。
传统写法我们先看看传统的写法 , 传统的写法主要用Mockito类的方法 。基本是when-then-invoke-verify形式 。
when(phoneBookRepository.contains(momContactName)) .thenReturn(false); phoneBookService.register(momContactName, momPhoneNumber); verify(phoneBookRepository) .insert(momContactName, momPhoneNumber);
BDD写法BDD写法主要是用BDDMockito类的方法 , 看起来是given–will-invoke-then的形式 。
given(phoneBookRepository.contains(momContactName)) .willReturn(false); phoneBookService.register(momContactName, momPhoneNumber); then(phoneBookRepository) .should() .insert(momContactName, momPhoneNumber);
动态mock有时候我们可能会遇到这个问题:在方法内部可能有循环或者递归 , 会多次调用其它对象的方法 , 但输入的参数不同 , 我们在mock的时候 , 期望它根据不同的输入参数返回不同的结果 。这个时候如果一个一个写given , 就需要写很多次 。但其实可以用动态mock来做 。它是基于InvocationOnMock来实现的 。
given(phoneBookRepository.contains(momContactName)) .willReturn(true);given(phoneBookRepository.getPhoneNumberByContactName(momContactName)) .will((InvocationOnMock invocation) -> invocation.getArgument(0).equals(momContactName) ? momPhoneNumber : null);phoneBookService.search(momContactName);then(phoneBookRepository) .should() .getPhoneNumberByContactName(momContactName);
Mockito的不足Mockito可以说是Java语言最流行的mock框架了 。但它不是所有对象都可以mock的 , 有一些限制 。
Mockito在3.4.0以前 , 是不能mock静态方法的 。这取决于它的底层实现 , 是使用动态代理来做的 。而动态代理是代理静态方法、final方法和private方法的 。
一般来说 , 我们不应该mock静态方法、final方法和private方法的 。但有时候可能会有这样的需求 , 比如Apache和guava框架 , 就使用了大量的静态方法提供一些工具类 。如果需要Mock的话 , 就得配合PowerMock等框架来实现 。但PowerMock框架目前还不支持JUnit 5 。
在Mockito 3.4.0 , 开始支持mock静态方法 , 底层是通过修改字节码来实现的 。但性能很差 , mock一个实例大概要一秒多 , 大家酌情使用 。
关于作者我是Yasin , 一个有颜有料又有趣的程序员 。
微信公众号:编了个程
个人网站:https://yasinshaw.com
推荐阅读
- 怎么从外观上区分HDMI1.4与HDMI2.0?
- MySQL主从不一致情形与解决方法
- sed 命令快速入门
- 教师|父母眼中的“铁饭碗”,我们应该听从吗?应该认可吗?
- 不买房怎么提取公积金?
- 好茶品质从第步开始,龙润茶十二年如日
- 篮球入门技巧简介
- 高尔夫球入门技巧 高尔夫球入门知识
- 聊聊从RPC到服务治理框架
- Python之爬虫入门教程