浅谈SpringContext的单元测试写法

这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

近期在为公司的旧代码写单元测试的时候,发现代码中有大量的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实现默认的返回。


作者:ShowMaker
链接:juejin.cn/post/699396… 来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 近期在为公司的旧代码写单元测试的时候,发现代码中有大量的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实现默认的返回。


作者:ShowMaker
链接:juejin.cn/post/699396… 来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 近期在为公司的旧代码写单元测试的时候,发现代码中有大量的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实现默认的返回。

猜你喜欢

转载自juejin.im/post/7032605265769791496