lsekfe 发表于 2022-4-18 09:20:14

浅谈SpringContext的单元测试写法

近期在为公司的旧代码写单元测试的时候,发现代码中有大量的Domain层代码使用了SpringContextUtil.getBean()这个方法,获取Sping中的Bean,这导致了普通的单元测试写法无法获取到这个对象,引发了空指针异常,导致单元测试失败,经过一番摸索,发现使用PowerMockito可以完美的解决问题。
  业务代码示例
  校验某个字段是否已经和数据库中的字段的属性重复。
 private void check(String code, String name) {
  if (SpringContextUtils.getBean(FieldRepo.class).checkFieldExist(code, name, getDepartmentId()) > 0) {
        throw new BusinessException("字段名称或code重复");
  }
  }
 单元测试示例
  单元测试的类名上要加@PrepareForTest(SpringContextUtils.class)注解。
  写法一
@Rule
  public ExpectedException thrown = ExpectedException.none();
  @Test
  public void createCheckAndProcessTest1() {
  PowerMockito.mockStatic(SpringContextUtils.class);
  PowerMockito.when(SpringContextUtils.getBean(FieldRepo.class)).thenReturn(fieldRepo());
  PowerMockito.when(fieldRepo.checkFieldExist(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(1);
  FieldBO fieldBO = new FieldBO();
  thrown.expect(BusinessException.class);
  thrown.expectMessage("字段名称或code重复");
  fieldBO.createCheckAndProcess();
  }
  public FieldRepo fieldRepo() {
  return new FieldRepo(){
  
  @Override
  public int countList(FieldPageInfoBO param) {
  return 0;
  }
  @Override
  public List<FieldBO> queryList(FieldPageInfoBO param) {
  return null;
  }
  @Override
  public int checkFieldExist(String code, String name, Long departmentId) {
  return 0;
  }
  ...
  }
  }
 这种写法有一种弊端,在Mock FieldRepo这个对象的时候,采用了新建对象的方式,又由于这个对象是一个接口类,一旦接口发生变更,单元测试这里的方法也必须随之修改,不然就会导致项目编译错误,引起单元测试失败。不是最优的写法,后来经过笔者摸索,找到了另一种更优美的写法。
  写法二
 @Mock
  FieldRepo fieldRepo;
  @Rule
  public ExpectedException thrown = ExpectedException.none();
  @Test
  public void createCheckAndProcessTest1() {
      PowerMockito.mockStatic(SpringContextUtils.class);
      PowerMockito.when(SpringContextUtils.getBean(FieldRepo.class)).thenReturn(fieldRepo);
      PowerMockito.when(fieldRepo.checkFieldExist(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(1);
      FieldBO fieldBO = new FieldBO();
      thrown.expect(BusinessException.class);
      thrown.expectMessage("字段名称或code重复");
      fieldBO.createCheckAndProcess();
  }
直接使用@Mock注解来mock这个FieldRepo对象,实现了与接口方法具体实现的解耦,这样无论FieldRepo怎么变动都不会影响单元测试,且Mock通过代理可以为FieldRepo实现默认的返回。


页: [1]
查看完整版本: 浅谈SpringContext的单元测试写法