单元测试Mockito使用心得

背景

团队推行单元测试,需要对主要逻辑serice层做单元测试,但是有些service会有外部接口调用或上游接口调用,而因为环境问题,这部分接口又无法掉通,为了解决这个问题,我接入了Mockito。

使用

1. 添加依赖

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

2. 具体使用

  1. @InjectMocks修饰需要测试的类
  2. @Mock修饰需要mock掉的类
  3. 初始化mock注解
  4. 声明调用特定方法时,传入指定参数,返回指定指
    • when(xxx.yyy(zzz)).thenReturn(aaa); // 当调用xxx.yyy()方法且入参是zzz时,返回aaa;如果入参不是zzz,则返回null。
    • when(xxx.yyy()).thenAnswer(t -> {});// 当调用xxx.yyy()方法时,没有返回值,执行一个自定义的函数体。
  5. 如果被mock的类在需要测试的类中是一个私有的字段,则需要反射修改私有字段的值,将其替换成mock代理类 ReflectionTestUtils.setField(testObject, “field”, mockObject);
  6. test原本需要测试的方法

例:

service调用链:

@Service
public class MerchantDataService  {
    
    @Reference
    private IMerchantUserService merchantUserService;

    public Object save(Object obj) {
        xxxxxx;
        ResponseEntity = merchantUserService.insert(xxxx);
        xxxxxx;
        return xxx;
    }

}

单元测试使用:

@SpringBootTest(classes = ApplicationStartup.class)
@ActiveProfiles("test")
public class MerchantDataServiceTest extends AbstractTransactionalTestNGSpringContextTests {

    @InjectMocks
    @Autowired
    private IMerchantDataService merchantDataService;

    @Mock
    private IMerchantUserService merchantUserService;

    @BeforeMethod(alwaysRun = true)
    public void initMock() {
        // 初始化mock注解
        MockitoAnnotations.initMocks(this);
        
        ResponseEntity resp = new ResponseEntity().setStatus(Status.SUCCESS);
        // 当执行merchantUserService.insert方法时,返回申明的对象
        when(merchantUserService.insert(new xxxx())).thenReturn(resp);
    }

    @Test
    public void testSave() {
          Object obj = new Object();
          Object resultObj = merchantDataService.save(obj);
          Assert.assertTrue(respOthers.success());
    }
}

以上