【问题标题】:spring boot which 'slice' to use for testing service componentspring boot 哪个“切片”用于测试服务组件
【发布时间】:2020-03-24 22:32:57
【问题描述】:

我正在使用 spring boot 开发一个 rest api。 它由标准层组成:控制器(@RestController)(处理传入的 http 请求并公开 api 端点),然后是服务层(@Service),最后是存储库层(@Repository)

我的问题是关于单元测试的。

为了测试我的控制器 - 我正在使用 mockito 模拟对服务层的调用。 还为了防止不必要地加载整个上下文,阅读了一些关于“弹簧片”的信息 所以要测试我的控制器 - 这是使用的注释:

@WebMvcTest

@ExtendWith(SpringExtension.class)

@WebMvcTest(controllers = TieredClaimController.class)
class TieredClaimControllerTest {

    @MockBean
    private TieredClaimService tieredClaimService;

    @Autowired
    private MockMvc mockMvc;

类似地测试我的 spring 数据存储库使用了另一个 spring slice 注释:@DataJpaTest

@ExtendWith(SpringExtension.class)
@DataJpaTest

@ContextConfiguration(initializers = {SalesRepositoryTest.Initializer.class})
public class SalesRepositoryTest {  

    @Autowired
    private SalesRepository repository; 

所以我可以看到用于 Web 端 (@WebMvcTest) 和数据库端 (@DataJpaTest) 的专用 spring slice 注释

但是,当我需要测试我的 @Service 注释类时,我应该使用哪个弹簧片? 我没有看到任何专门用于服务层的

我问的原因是我以这种方式使用它: 注意(对存储库的调用是模拟的,所以基本上我的服务层单元测试是隔离的)

@ExtendWith(SpringExtension.class)
@SpringBootTest
class TieredClaimServiceTest {

    @Autowired
    private TieredClaimService tieredClaimService;  

    @MockBean
    private SalesRepository salesRepository;

但是问题是 - 当我运行这些单元测试时,会调用一些不必要的 jpa / hibernate 代码。

如何防止这种情况发生?

2019-11-29 | 21:04:17.293 | SpringContextShutdownHook |调试 | org.hibernate.SQL |如果存在则删除表 discount_tiers Hibernate:如果存在则删除表 discount_tiers 2019-11-29 | 21:04:17.293 | SpringContextShutdownHook |调试 | org.hibernate.SQL |如果存在则删除表商品 Hibernate:如果存在则删除表商品 2019-11-29 | 21:04:17.293 | SpringContextShutdownHook |调试 | org.hibernate.SQL |如果存在则删除表销售额 Hibernate:如果存在则删除表销售额 2019-11-29 | 21:04:17.293 | SpringContextShutdownHook |调试 | org.hibernate.SQL |如果存在则删除表用户 Hibernate:如果存在则删除表用户 2019-11-29 | 21:04:17.309 | SpringContextShutdownHook |调试 | org.hibernate.SQL |如果存在则丢弃序列 hibernate_sequence Hibernate:如果存在则丢弃序列 hibernate_sequence*

2019-11-29 | 21:04:17.309 | SpringContextShutdownHook |调试 | o.h.t.s.TypeConfiguration$Scope |从 SessionFactory [org.hibernate.internal.SessionFactoryImpl@17fddecd] 中取消范围 TypeConfiguration [org.hibernate.type.spi.TypeConfiguration$Scope@89296ce]

我猜这些会出现在日志中,因为在我的 application.properties(在 /src/test/resources 下)我有这个:

spring.jpa.hibernate.ddl-auto=create-drop

但是,当我对存储库层进行单元测试时,我需要此配置,因此我无法删除或移除它

所以对于我的服务层,是否有任何弹簧切片注释? 当我测试与数据库/存储库隔离的服务层时,如何避免休眠/jpa 调用或加载,因为该层是模拟的?

EDIT1: 根据下面的答案,我想我没有提供我的服务类的完整详细信息: 我尝试了以下方法,但由于又注入了一个服务类,所以我遇到了问题:( DiscountTierService 也被注入到 TieredClaimServiceImpl 中)

这是完整的例子:

@Service
public class TieredClaimServiceImpl implements TieredClaimService {

//@Autowired
private MerchRepository merchRepository;

//@Autowired
private SalesRepository salesRepository;

@Autowired
private DiscountTierService discountTierService;

private static final Logger LOGGER = LoggerFactory.getLogger(TieredClaimServiceImpl.class);

public TieredClaimServiceImpl() {       
}

@Autowired
public TieredClaimServiceImpl(MerchRepository merchRepository,SalesRepository salesRepository) {
    this.merchRepository = merchRepository;
    this.salesRepository = salesRepository;
}

@Override
//public List<? extends MerchSales>  calculateClaim(String code,LocalDate fromDate,LocalDate toDate) {
public List <TieredClaimDto>  calculateClaim(ClaimRequestDto claimRequestDto,String xAppCorelationId) throws SystemException {

这是修改后的测试类:

@ExtendWith(SpringExtension.class)
class TieredClaimServiceTest {

private TieredClaimService tieredClaimService;  


@MockBean
private SalesRepository salesRepository;

@MockBean   
private MerchRepository merchRepository;

@BeforeEach
void setUp() {
    tieredClaimService = new 
    TieredClaimServiceImpl(merchRepository,salesRepository);
}




//@Autowired
//private DiscountTierService discountTierService;
@ParameterizedTest
@ValueSource(strings = {"merch", "sales"})
@DisplayName("xyz ")
void tieredClaimPositiveScenarioWithinTier(String sourceType) throws Exception {

在实际的服务类中,我得到了一个注入,因为 DiscountTierService 没有被注入:

我在以下代码行得到了一个 NPE:

@Override
public List <TieredClaimDto>  calculateClaim(ClaimRequestDto claimRequestDto,String xAppCorelationId) throws SystemException {


    /** get the discount tier config data **/
    **List<DiscountTierDto> discountTierList = discountTierService.get();**

【问题讨论】:

  • 你在服务中使用了构造函数注入还是字段注入?
  • 感谢我将其从字段注入更改为构造函数注入 - 感谢您的输入我已为我的问题添加了更多详细信息

标签: java spring spring-boot unit-testing mocking


【解决方案1】:

对于您的服务层,您不需要/不需要弹簧片。 您只需使用 JUnit 测试您的 service.class 并使用 Mockito 模拟存储库,就像您在控制器中使用服务所做的那样。

如果您需要 SpringContext,也可以使用 @RunWith(MockitoJUnitRunner.class) 或 @RunWith(SpringRunner.class) 注释您的测试类...

【讨论】:

  • 谢谢 - 请查看更新后的问题。我的故障详细信息不完整添加为编辑 1 - 由于正在向我正在测试的服务中注入额外的服务而仍然遇到问题 - 现在当我测试时 - 由于我认为没有 spring 上下文,因此该服务没有被注入我做事的方式?
猜你喜欢
  • 2021-11-30
  • 2021-03-15
  • 1970-01-01
  • 2015-06-24
  • 2016-10-31
  • 1970-01-01
  • 2015-08-02
  • 1970-01-01
  • 2017-08-01
相关资源
最近更新 更多