简体   繁体   English

Spring应用程序的集成测试

[英]Integration tests of Spring application

I am trying to implement integration tests for my Tomcat application, but my issue is that the application is launched separately from the tests so the tests cannot access the application context and neither the database. 我正在尝试为Tomcat应用程序实施集成测试,但是我的问题是该应用程序是与测试分开启动的,因此测试无法访问应用程序上下文,也不能访问数据库。

My idea is running the tests "within" the running application, so I can @Autowire EntityManager and check for instance the state of the database during testing or even create database entities for testing. 我的想法是在正在运行的应用程序内运行测试,因此我可以@Autowire EntityManager并在测试过程中检查例如数据库的状态,甚至可以创建数据库实体进行测试。

My only idea of doing this is to actually run the application programmatically from the tests as ClassPathXmlApplicationContext("applicationContext.xml") and the access the Context. 我这样做的唯一想法是从测试中实际以编程方式以ClassPathXmlApplicationContext("applicationContext.xml")运行应用程序并访问Context。 This would work, but it would be very hard for debugging as we wouldn't be able to use Hotswapping during the testing. 这可以工作,但是调试起来非常困难,因为在测试期间我们将无法使用Hotswapping。 Also I guess the server would be stopped as soon as the tests would end. 我也猜想服务器将在测试结束后立即停止。 I guess that is not the best and correct solution. 我猜这不是最佳和正确的解决方案。

EDIT: 编辑:

My question was probably unclear, so I will try to clarify. 我的问题可能不清楚,因此我将尝试澄清。

I have a Tomcat application with Spring and Hibernate. 我有一个Spring和Hibernate的Tomcat应用程序。 The Spring beans and Hibernate database connection is initialised when the Tomcat application is started. 启动Tomcat应用程序时,将初始化Spring Bean和Hibernate数据库连接。 The issue is how to run the tests of the active Spring beans from methods annotated with @Test in src/test/java which are started separately. 问题是如何从src/test/java中用@Test注释的方法(分别启动)运行活动的Spring Bean的src/test/java

Consider this class: 考虑此类:

@Component
class MyRepository {

    @Autowired
    EntityManager em;

    @Transactional
    public void myMethod(MyEntity entity) {
        // do some job with entity
        ...
        em.flush();
    }
}

This class will be initialised with Tomcat as a MyRepository bean. 此类将以Tomcat初始化为MyRepository Bean。

To test it, I cannot just call new MyRepository().myMethod(...) - I need to access the bean. 为了测试它,我不能只调用new MyRepository().myMethod(...) -我需要访问bean。 The issue is accessing the bean from the @Test method: 问题是从@Test方法访问bean:

@Test
void testMyRepository() {
    Item item = ...
    // then use the repository to handle the entity 
    context.getBean(MyRepository.class).myMethod(item);

    // then assert the state of the database
    context.getBean(EntityManager.class).find(Item.class, ...) ...
}

I can probably get the context in the initialisation of the tests with 我可能可以在测试的初始化中获得context

ApplicationContext context = ClassPathXmlApplicationContext("applicationContext.xml");

But it would mean launching the whole application each time the tests are started. 但这意味着每次测试开始时都要启动整个应用程序。 The better solution would be if the application could run separately from the tests. 更好的解决方案是应用程序可以与测试分开运行。

Hope my problem is more clear now. 希望我的问题现在更加清楚。

I would suggest you to use the SpringRunner to start the Spring application context and perform your tests on that running instance. 我建议您使用SpringRunner来启动Spring应用程序上下文并在该正在运行的实例上执行测试。 You can customize the context the way it doesn't contain parts you don't want to tests and you can create mocks for components that require some external resources (REST clients and such). 您可以使用不包含您不想测试的部分的方式自定义上下文,并且可以为需要一些外部资源(REST客户端等)的组件创建模拟。 Take a look at the Spring docs or Spring Boot docs . 看一下Spring文档Spring Boot文档

If multiple tests use the same Spring context configuration, the context is started just once and reused. 如果多个测试使用相同的Spring上下文配置,则该上下文仅启动一次并重新使用。 So it's good to have it's configuration in a parent class of your tests. 因此,最好在测试的父类中进行配置。 You can autowire any Spring bean into your test and test it. 您可以将任何Spring bean自动连接到测试中并进行测试。

You can use an in-memory database (such as H2 ) instead of a production one, so your tests are not dependent on an external infrastructure. 您可以使用内存数据库(例如H2 )而不是生产数据库,因此您的测试不依赖于外部基础结构。 To initialize the database, use tools like Flyway or Liquibase . 初始化数据库,使用一样的工具迁飞Liquibase To clear the database before each test, you can use the @Sql annotation. 要在每次测试之前清除数据库,可以使用@Sql批注。

You can find many examples of projects with such tests, for example my own demo . 您可以找到许多带有此类测试的项目示例,例如我自己的demo

If you want to test an external system, I would suggest something like JMeter . 如果要测试外部系统,建议使用JMeter之类的东西。

Unfortunately you cant mirror your classes and use them in your tests. 不幸的是,您无法镜像您的类并在测试中使用它们。 Thats a big disadvantage of web services. 那就是Web服务的一个很大的缺点。 They always depend on user / machine interaction. 它们始终取决于用户/机器的交互。 With a lot of effort you can extract the functionality of the essential classes or methods and construct test scenarios etc. with jUnit. 您可以花费很多精力使用jUnit提取基本类或方法的功能并构建测试方案等。 The Overview of your possibilities: 您的可能性概述:

  • special drivers and placeholders 特殊驱动器和占位符
  • you can use a logger with detailed log-level and file output. 您可以使用具有详细日志级别和文件输出的记录器。 Then you created scenarios with the expected result and compare it with your log files. 然后,您创建了具有预期结果的方案,并将其与日志文件进行比较。

  • Capture replay tools. 捕获重放工具。 They record your exection and replay them for monitoring. 他们记录您的执行并重播以进行监视。

  • I can also recommend using Selenium for the frontend tests. 我也建议使用Selenium进行前端测试。

Hope it helped. 希望能有所帮助。

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

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