春季启动:将测试中的bean注入Web环境

时间:2020-01-26 08:30:39

标签: java spring spring-boot junit junit5

我正在为示例应用程序构建一些集成测试,并且想知道是否可以在测试本身中创建一些测试数据,然后将其注入到正在运行的服务器中。我不想模拟数据,因为我希望我的测试能够遍历整个堆栈。

我了解Spring Boot文档说服务器和测试在2个单独的线程中运行,但是是否可以传递相同的上下文?

我到目前为止的代码:

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ArtistResourceTests {
    @Autowired
    private TestRestTemplate restTemplate;

    @Autowired
    private ArtistRepository artistRepository;

    @Test
    @Transactional
    public void listReturnsArtists() {
        Artist artist = new DataFactory().getArtist();
        this.artistRepository.save(artist);

        ParameterizedTypeReference<List<Artist>> artistTypeDefinition = new ParameterizedTypeReference<List<Artist>>() {};
        ResponseEntity<List<Artist>> response = this.restTemplate.exchange("/artists", HttpMethod.GET, null, artistTypeDefinition);

        assertEquals(1, response.getBody().size());
    }
}

但这将返回0个结果而不是1个结果。

2 个答案:

答案 0 :(得分:1)

我认为您不与某些远程运行的服务器交互。

SpringBootTest批注在测试内部本地启动整个微服务。 否则,如果您的测试只是对远程服务器的一系列调用,则您实际上不需要@SpringBootTest(也完全不需要spring boot:))。

因此,您在测试内部就有一个应用程序上下文。 现在,您要问如何预填充数据。这太广泛了,因为您没有指定数据的确切存储位置以及涉及的数据持久层(RDBMS,Elasticsearch,Mongo等)?

一种可能的通用方法是使用可以具有方法beforeTestMethod的{​​{3}}。

启动了应用程序上下文,因此您可以真正以自定义方式准备数据并将其保存到您选择的数据库中(通过将DAO注入侦听器或其他方式)。

如果您使用Flyway,另一种有趣的方式是在src/test/resources/data文件夹中提供迁移,以便flyway在测试期间自动执行迁移。

更新

评论指出,在这种情况下,假设数据源配置正确并且确实提供了与H2的连接,则使用H2 DB,最简单的方法是运行带有数据插入的SQL脚本:

@Sql(scripts = {"/scripts/populateData1.sql", ..., "/scripts/populate_data_N.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
public void myTest() {
...
}

现在,如果您需要使用

this.artistRepository.save(artist);

然后spring不再关心线程。只要“数据”是一个bean(或资源),它就可以注入任何数据,因为您正在使用对象(艺术家),所以它必须是一个bean。

因此,使用bean TestConfiguration创建Artist,并确保其与test在同一程序包中(以便spring boot test扫描过程将加载配置),并使用@Autowired将其注入测试中。通常:

@TestConfiguration
public class ArtistsConfiguration {

   @Bean 
   public Artist artistForTests() {
       return new Artist(...);
   }
}


@Import(ArtistsConfiguration.class)
@SpringBootTest
public class MyTest {

   @Autowired
   private Artist artist;

   ....
}

答案 1 :(得分:0)

您可以使用@ContextConfiguration,如下所示:

@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("test")
@ContextConfiguration(locations = {"/testApplicationContext.xml"})
public class TestGetPerson {

    @Autowired
    private PersonService personService;
...

然后在testApplicationContext中指定Spring应该扫描的包:

<context:component-scan base-package="nl.example.server.service"/>
<context:component-scan base-package="nl.example.server.test.db"/>

可能有一个注释可以达到相同目的。 我要做的是使Spring扫描的大多数软件包与实时应用程序中的软件包相同,除了数据库组件之外:我使用内存H2数据库进行测试。 Profiles注释告诉Spring在测试中要使用哪些类。 另外,您可以将某些类配置为Mockito模拟(使用扫描包中的@Configuration):

@Configuration
@Profile("test")
public class CustomerManagerConfig {
@Bean("customerManager")

    public CustomerManager customerManager() {
        return Mockito.mock(CustomerManager.class);
    }
}

这不会在单独的服务器上运行测试数据,但是会在与您的应用程序环境紧密相关的环境中运行测试。

关于您的问题,您可以创建自己的模拟,以将测试数据注入所需的任何组件中,而不必使用Mockito模拟。