浅谈业务代码中不常见场景的单元测试写法

145 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情

使用构造器方式初始化

项目中大量使用了构造器方式注入,这种注入方式的好处有下列几种。

  • 使用final关键字,保证依赖不可变
  • 省去了我们对其检查,保证依赖不为空
  • 保证返回客户端(调用)的代码的时候是完全初始化的状态
  • 避免了循环依赖
  • 提升了代码的可复用性

特别是循环依赖检查这方面,随着业务的扩展,当初的代码结构设置的不够合理,对代码不够熟悉等因素可能造成循环依赖的情况。之前发生过项目上线后,点击了相关功能才爆出系统异常,原因就是产生了循环依赖。使用了构造器注入方式后,在项目启动的时候,就会抛出BeanCurrentlyInCreationException:Requested bean is currently in creation: Is there an unresolvable circular reference从而提醒避免循环依赖。

这种场景可以直接使用@Mock和@InjectMocks

业务代码示例

@Service
public class EventService implements ModuleDtoQuery<EventDetailDTO> {

    private final AppService appService;
    private final EventRepo repo;

    @Autowired
    public EventService(AppService appService,
                        EventRepo repo) {
        this.appService = appService;
        this.repo = repo;
    }
 }

单元测试代码示例

@RunWith(PowerMockRunner.class)
public class EventServiceTest {
    @Mock
    AppService appService;
    @Mock
    EventRepo repo;
    @InjectMocks
    EventService eventService;

    @Test
    public void queryList() {
    ...
    }   
}

构造器注入中加入了List -> Map

通过接口注入了多个实现,再通过List转Map来达到快速获得接口、减少代码的目的。

业务代码示例

@Service
public class CatalogService {

    private final CatalogRepo catalogRepo;
    private final CatalogAssembler catalogAssembler;
    private final Map<Integer, CountByCatalog> countByCatalogMap;

    @Autowired
    public CatalogService(CatalogRepo catalogRepo,
                          CatalogAssembler catalogAssembler,
                          List<CountByCatalog> countByCatalogList) {
        this.catalogRepo = catalogRepo;
        this.catalogAssembler = catalogAssembler;
        this.countByCatalogMap = countByCatalogList.stream()
                .collect(Collectors.toMap(CountByCatalog::getCatalogType, v -> v));
    }
    
}

单元测试代码示例

首先使用@Mock来模拟这个接口的集合,再手动写一些实现类,这样就可以达到我们模拟的要求了。

@RunWith(PowerMockRunner.class)
@PrepareForTest({SpringContextUtils.class})
public class CatalogServiceTest {

    @Mock
    CatalogRepo catalogRepo;

    @Mock
    CatalogAssembler catalogAssembler;

    @Mock
    List<CountByCatalog> countByCatalog = Arrays.asList(new CountByCatalog() {
        @Override
        public int getCatalogType() {
            return 0;
        }
    });

    @InjectMocks
    CatalogService catalogService;
    
 }