简体   繁体   English

Spring Boot:将测试中的 bean 注入 Web 环境

[英]Spring boot: Inject beans from tests into web environment

I am building some integration tests for my sample application and was wondering if I can create some test data in my tests itself and then inject it through to the server that is running.我正在为我的示例应用程序构建一些集成测试,并且想知道是否可以在我的测试中创建一些测试数据,然后将其注入正在运行的服务器。 I prefer not to mock my data because I want my test to run through the whole stack.我不想模拟我的数据,因为我希望我的测试在整个堆栈中运行。

I understand the Spring Boot documentation is saying that the server and the tests are running in 2 separate threads, but is it possible to pass the same context through?我知道 Spring Boot 文档说服务器和测试在 2 个单独的线程中运行,但是是否可以传递相同的上下文?

The code I have so far:我到目前为止的代码:

@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());
    }
}

But this returns 0 results instead of 1 result.但这会返回 0 个结果而不是 1 个结果。

I think you don't interact with some remotely running server.我认为您不会与某些远程运行的服务器进行交互。

SpringBootTest annotation starts the whole microservice locally inside the test. SpringBootTest注解在测试内部本地启动整个微服务。 Otherwise if your test is just a series of calls to the remote server, you don't really need @SpringBootTest (and don't need spring boot at all :) ).否则,如果您的测试只是对远程服务器的一系列调用,则您实际上并不需要@SpringBootTest (并且根本不需要 spring boot :))。

So you have an application context right inside the test.所以你在测试中有一个应用程序上下文。 Now you're asking how to pre-populate the data.现在您要问的是如何预填充数据。 This is too broad, since you don't specify where exactly the data is stored and which data persistence layers are involved (RDBMS, Elasticsearch, Mongo, ...)?这太宽泛了,因为您没有指定数据的确切存储位置以及涉及哪些数据持久层(RDBMS、Elasticsearch、Mongo 等)?

One possible general-purpose way is using Test Execution Listener that can have a method beforeTestMethod .一种可能的通用方法是使用可以具有方法beforeTestMethod测试执行侦听器

The application context is started so you can really prepare the data in a custom way and save it to the database of your choice (via injected DAOs into the listener or something).应用程序上下文已启动,因此您可以真正以自定义方式准备数据并将其保存到您选择的数据库中(通过将 DAO 注入侦听器或其他方式)。

Another interesting way if you use Flyway is to provide migrations in the src/test/resources/data folder so that flyway will execute migrations automatically during the test.如果您使用 Flyway,另一个有趣的方法是在src/test/resources/data文件夹中提供迁移,以便 flyway 在测试期间自动执行迁移。

Update更新

The comment states, that H2 DB is used, in this case, assuming the datasource is configured correctly and indeed provides connections to H2, the easiest way is running SQL scripts with data inserts:评论指出,在这种情况下,使用 H2 DB,假设数据源配置正确并且确实提供了到 H2 的连接,最简单的方法是运行带有数据插入的 SQL 脚本:

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

Now if you have to work with现在如果你必须与

this.artistRepository.save(artist);

Then spring doesn't care about threads.那么 spring 不关心线程。 It can inject any data as long as the "data" is a bean (or resource), since you're working with objects (Artist), it has to be a bean.只要“数据”是一个 bean(或资源),它就可以注入任何数据,因为您正在处理对象(艺术家),它必须是一个 bean。

So create TestConfiguration with bean Artist , make sure its in the same package as test (so that spring boot test scanning process will load the configuration) and inject it into the test with @Autowired as usual:因此,使用 bean Artist创建TestConfiguration ,确保它与 test 在同一个包中(以便 spring boot 测试扫描过程将加载配置)并像往常一样使用 @Autowired 将其注入测试:

@TestConfiguration
public class ArtistsConfiguration {

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


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

   @Autowired
   private Artist artist;

   ....
}

You can use @ContextConfiguration, like so:您可以使用@ContextConfiguration,如下所示:

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

    @Autowired
    private PersonService personService;
...

Then in testApplicationContext you specify the packages Spring should scan:然后在 testApplicationContext 中指定 Spring 应该扫描的包:

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

There may be an annotation that achieves the same thing.可能有一个注释可以实现相同的目的。 What I do is make Spring scan most packages the same as in the live application, except the database components: I use an inmemory H2 database for testing.我所做的是使 Spring 扫描大多数包与实时应用程序中的相同,除了数据库组件:我使用内存中的 H2 数据库进行测试。 The Profiles annotation tells Spring what classes are to be use in test. Profiles 注释告诉 Spring 在测试中要使用哪些类。 Also, you can configure (using @Configuration in a scanned package) certain classes to be Mockito mocks:此外,您可以配置(在扫描包中使用@Configuration)某些类作为 Mockito 模拟:

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

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

This doesn't run your test data against a separate server, but it does run the test in an environment that ressembles your application's environment as closely as you like.这不会针对单独的服务器运行您的测试数据,但它会在与您的应用程序环境尽可能相似的环境中运行测试。

Regarding your question, instead of using a Mockito mock, you can create your own mock that injects your test data in any of the components you like.关于您的问题,您可以创建自己的模拟,将测试数据注入您喜欢的任何组件中,而不是使用 Mockito 模拟。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM