首页 > 解决方案 > 有没有办法在 Spring Boot 中测试没有 Web 或持久层的嵌套对象?

问题描述

我正在使用 JUnit5 来测试 Spring Boot 应用程序。我想测试一个@Service使用@Autowired字段的对象。我想模拟@Service我的测试对象间接使用的另一个对象。具体来说,我有以下(高度简化的)设置:

被测对象:

@Service
public class MainService {
    
    private @Autowired SubService subService;
    
    public String test() {
        return subService.test();
    }

}

SubService

@Service
public class SubService {
    
    private @Autowired StringService stringService;

    public String test() {
        return stringService.test();
    }

}

StringService

@Service
public class StringService {

    public String test() {
        return "Real service";
    }

}

使用的测试类:

@SpringBootTest
public class MainServiceTest {

    private @Autowired MainService mainService;
    private @MockBean StringService stringService;
    
    @BeforeEach
    public void mock() {
        Mockito.when(stringService.test()).thenReturn("Mocked service");
    }
    
    @Test
    public void test() {
        assertEquals("Mocked service", mainService.test());
    }
    
}

如果我将测试类作为 a 运行,则上述方法有效@SpringBootTest,但这会加载完整的应用程序并且非常慢。我也想避免@WebMvcTest,因为我不需要 Web 服务器,或者@DataJpaTest因为我不需要持久性。我不想模拟SubService,因为它包含我想与MainService.

我尝试了以下方法:

有没有办法在不加载 web 服务器或持久层的情况下使用 spring 依赖注入系统,或者不使用 Spring 测试但允许“嵌套”依赖注入?

标签: springspring-bootjunitmockito

解决方案


您可以使用分析(即 Spring @Profile)来避免加载整个应用程序。它看起来像下面这样:

@Profile("test")
@Configuration
public class TestConfiguration {
    @Bean
    public MainService mainService() {
        return new MainService();
    }

    @Bean
    public SubService subService() {
        return new SubService();
    }
    // mock the StringService
    @Bean
    public StringService stringService() {
        return Mockito.mock(StringService.class);
    }
 
}

然后将该配置文件与 `@SpringBootTest(classes = TestConfiguration.class) 一起使用,它将如下所示:

@ActiveProfiles("test")
@SpringBootTest(classes = TestConfiguration.class)
class MainServiceTest {

    @Autowired
    private MainService mainService;

    @Test
    public void test() {
        // configure behavior using apis like when(), basically however you 
        // want your mock to behave
    }

}

这将只加载类中定义的 bean TestConfiguration。注意:由于您的问题更多是关于如何避免加载整个应用程序,因此我已经回答了重点。上述方法将完成工作,但我更喜欢构造函数接线,而不是任何一天的任何其他依赖注入模式,它更容易维护和测试(比如你想要模拟的情况)。


推荐阅读