如何在单元测试中对写数据库进行测试?

2020-12-01 18:04:07 浏览数 (1)

首先问一个问题,在接口测试中,验证被测接口的返回值是否符合预期是不是就够了呢?

场景

转账是银行等金融系统中常见的一个场景。在在最近的一个针对转账服务的单元测试中,笔者就遇到了上述问题。一个极端简化的转账申请如下图:

在一个B端用户通过转账服务接口发起转账申请后,转账服务接口在完成发起转账申请的过程中,在完成各项合法性校验,确定可以发起转账时,会从外部流水号服务那里申请到一个全局唯一且单调递增的流水号,该流水号将作为转账申请提交成功的返回值向申请方返回。同时,该流水号将作为转账申请记录的一部分,写入后台数据库等待后续审核。

从上述介绍中,我们得以了解到,这里的转账服务接口只是完成了申请的接收工作。转账申请需要后续被人工审核后才能完成实际的转账。

实现伪代码

代码语言:javascript复制
public class EntryRepository {
...
    public void save(Entity entity) {
        System.out.println(entity.getFlowNo);
    }
}

@Service
public class EntryService  throws Exception{
    @Autowired
    private EntryRepository entryReposity;
    
    @Autowired
    private FlowNoService flowNoService;
    
@Transactional
    public String submit(Entity entity) {
        validEntity(entity);
    entity.setFlowNo(flowNoService.getNextFlowNo()); //流水号
       entity.setStatus("SUBMITTED"); //已提交
        entryReposity.save(entity);
        return entity.getFlowNo();
    }
}

以上是一个极简的代码实现逻辑,完成了申请单检查、流水号获取、数据库保存以及接口返回。

第一个单元测试- 请求/返回

代码语言:javascript复制
public class EntryServiceTest {
@InjectMocks
private EntryService entryService;
@Mock
private EntryRepository entryReposity;
@Mock
private FlowNoService flowNoService;
@Test
public void shouldReturnFlowNo(){
Entity entity= new entity;
entity.setAmount("一个亿");
String flowNo="20200307000001";
Mockito.when(flowNoService.getNextFlowNo()).thenReturn(flowNo);
assertThat(entryService.submit(entity)).isEqualTo(flowNo);
}
}

第一个用例首先验证了接口的返回值。

第二个单元测试-写库

代码语言:javascript复制
@Captor
private ArgumentCaptor<Entity> captor;
@Test
public void shouldCapture() {

    Entity entity= new entity;
    entity.setAmount("一个亿");
    String flowNo="20200307000001";
    Mockito.when(flowNoService.getNextFlowNo()).thenReturn(flowNo);
    Mockito.verify(entryReposity,times(1)).save(captor.capture());
    Entity captured= captor.getValue();
        
    Entity expected= new Entity();
        expected.setFlowNo(flowNo);
        expected.setStatus("SUBMITTED");
    assertThat(captured).isEqualToComparingOnlyGivenFields(expected,"flowNo","status");

}
}

在之前的测试用例类中,我们再添加第二个单元测试用例,来验证数据库写库的数据是否符合预期结果。

第三个用例 -- 两笔申请?

如何对两笔申请进行单元测试,Mock又如何写?这个就留给读者自行练习了。

如果不是写库,而是通过MQ对外发布?又如何进行测试呢?

小结

本案例演示了如何使用Mockito提供的Capture特性来验证方法的传参,同时也展示了如何使用AssertJ进行对象的多个属性的断言。

0 人点赞