51Testing软件测试论坛

标题: 浅谈SpringContext的单元测试写法 [打印本页]

作者: lsekfe    时间: 2022-4-18 09:20
标题: 浅谈SpringContext的单元测试写法
近期在为公司的旧代码写单元测试的时候,发现代码中有大量的Domain层代码使用了SpringContextUtil.getBean()这个方法,获取Sping中的Bean,这导致了普通的单元测试写法无法获取到这个对象,引发了空指针异常,导致单元测试失败,经过一番摸索,发现使用PowerMockito可以完美的解决问题。
  业务代码示例
  校验某个字段是否已经和数据库中的字段的属性重复。
  1.  private void check(String code, String name) {
  2.     if (SpringContextUtils.getBean(FieldRepo.class).checkFieldExist(code, name, getDepartmentId()) > 0) {
  3.         throw new BusinessException("字段名称或code重复");
  4.     }
  5.   }
复制代码
 单元测试示例
  单元测试的类名上要加@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实现默认的返回。








欢迎光临 51Testing软件测试论坛 (http://bbs.51testing.com/) Powered by Discuz! X3.2