mockito使用心得

2018-03-10  本文已影响0人  EmilioWong

初遇mockito

初次看到mockito的时候,是在开发者头条读的一篇关于github上2017年开源项目使用的jar包统计的文章。mockito是排名第二还是第三忘记了(第一是junit,可见对于单元测试的重视程度及java业内对单元测试框架选择的统一)。当时引起我注意的是因为mock这个词,正好前不久了解了下mock,于是就百度了mockito,发现mockito正好可以解决api调用的模拟问题,于是当晚就试了下这个工具。

依赖

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.13.0</version>
    <scope>test</scope>
</dependency>

用法

对要模拟返回的类使用@Mock注解。如果需要测试的类不是被模拟的类,且需要被模拟的类注入的话使用@InjectMocks注解,还要调用MockitoAnnotations.initMocks方法注入。下为例子

@InjectMocks
private AnalyseService analyseService;
@Mock
private FetchService fetchService;
@Before
public void setup() throws IOException {
    MockitoAnnotations.initMocks(this);
}

模拟时分为两种语法

when(fetchService.fetchBankCard("")).thenReturn(mockBankCard);
Mockito.doReturn(mockEducation).when(fetchService).fetchEducation(Mockito.any(String.class), Mockito.any(String.class));

when、thenReturn、doReturn、是Mockito类里的静态方法,导包时候如果不加入static关键词的话,就需要加上Mockito. 类似Assert。

import static org.mockito.Mockito.*;

碰到的问题

一开始一直运行不起来,各种找资料后,发现在类上加上如下注解就可以了。

@TestExecutionListeners(listeners = {SpringBootDependencyInjectionTestExecutionListener.class, ServletTestExecutionListener.class})

但是在spring boot的其他测试类里,就算没有使用mock的话,不加上面注解的情况下是无法运行的,具体原因不明。

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = Application.class)

例子

@Test
public void testMockHandleAuthMobile() throws IOException {
    final String mockStr = "{\"orderNo\":\"201709061056396790389\",\"data\":{\"result\":\"T\",\"message\":\"信息验证通过\"},\"rc\":\"0000\",\"msg\":\"查询成功\"}";
    Map mock = new ObjectMapper().readValue(mockStr, Map.class);
    when(fetchService.fetchAuthMobile(anyString(), anyString(), anyString())).thenReturn(mock);

    Boolean result = analyseService.handleAuthMobile("", "", "");
    assertTrue(result);
@Test
public void testMockFailHandleAuthMobile() throws IOException {
    final String mockStr = "{\"orderNo\":\"201709061056396790389\",\"data\":{\"result\":\"F\",\"message\":\"信息验证不通过\"},\"rc\":\"0000\",\"msg\":\"查询成功\"}";
    Map mock = new ObjectMapper().readValue(mockStr, Map.class);
    when(fetchService.fetchAuthMobile(anyString(), anyString(), anyString())).thenReturn(mock);

    Boolean result = analyseService.handleAuthMobile("", "", "");
    assertFalse(result);
}

@Test
public void testMockNullHandleAuthMobile() throws IOException {
    final String mockStr = "{\"rc\":\"1000\",\"msg\":\"apikey校验失败\"}";
    Map mock = new ObjectMapper().readValue(mockStr, Map.class);
    when(fetchService.fetchAuthMobile(anyString(), anyString(), anyString())).thenReturn(mock);

    Boolean result = analyseService.handleAuthMobile("", "", "");
    assertNull(result);
}

如上mockStr是模拟返回对象的字符串,转换为Map后,使用when(). thenReturn()将模拟的数据返回。

一些思考


updatedAt 2018年03月23日14:17:12

mockito干不了的事情

今天又用了一下mockito,发现一些问题。先附上源码

@Service
public class UserService implements InterfaceEntityService , UserDetailsService{

    @Autowired
    private InitService initService;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private RoleRepository roleRepository;

    @Autowired
    private SmsService smsService;

……省略其他内容
}

userService是我需要的测试类,需要测试的方法是注册方法,需要用到短信校验,smsService是需要模拟的类,用于短信的发送和校验。因为我并不想要测试短信发送及校验的逻辑,我需要对smsService进行mock处理,再注入到userService。
这时候问题来了。我只把smsService做了mock,在测试注册方法的时候需要用到roleRepository的方法,去获取角色,而roleRepository报了NPE。userService使用了@InjectMocks注解,smsService因为mock注入进去了,而initService、userRepository、roleRepository等都无法注入。查了资料后,找不到方法可以将不想要mock的类自动注入进去。最后,只能再将roleRepository mock处理一下,注入到userService,返回角色。
此外,在查看官方文档额过程中,官方文档也给出了mockito干不了的事,这个可以解释一些思考力的第三点

Do not mock types you don't own
Don't mock value objects
Don't mock everything
Show some love with your tests

以上是github上mockito wiki里的Remember

在FAQ中,也写了mockito的其他一些问题

Mockito 2.x specific limitations
Can I mock static methods?

No. Mockito prefers object orientation and dependency injection over static, procedural code that is hard to understand & change. If you deal with scary legacy code you can use JMockit or Powermock to mock static methods.

Can I mock private methods?

No. From the standpoint of testing... private methods don't exist. More about private methods here.

Can I verify toString()?

No. You can stub it, though. Verification of toString() is not implemented mainly because:

When debugging, IDE calls toString() on objects to print local variables and their content, etc. After debugging, the verification of toString() will most likely fail.
toString() is used for logging or during string concatenation. Those invocations are usually irrelevant but they will change the outcome of verification.

上一篇 下一篇

猜你喜欢

热点阅读