简体   繁体   English

与JPA和Spring的集成测试

[英]integration testing with JPA and Spring

I have a Spring/JPA web application that I would like to write some tests for. 我有一个Spring / JPA Web应用程序,我想为其编写一些测试。 Ideally I would like to be able to: 理想情况下,我希望能够:

  • create the test DB schema (from the JPA annotated classes) once before the tests are run 在运行测试之前,一次创建测试数据库模式(从带有JPA注释的类)
  • run each test method in it's own transaction which is rolled back when the test completes 在自己的事务中运行每个测试方法,该方法在测试完成时会回滚
  • specify the (DbUnit) dataset to be loaded for each test either at the per-class or per-method level. 在类或方法级别上指定要为每个测试加载的(DbUnit)数据集。 The test data should be loaded after the transaction has started so that the test data will also be rolled back when the test completes 应在事务开始后加载测试数据,以便在测试完成时也回滚测试数据
  • inject Spring beans into the test class 将Spring bean注入测试类

I'm aware that Spring provides classes which can provide the transactional behaviour I'm seeking. 我知道Spring提供了可以提供我正在寻找的事务行为的类。 Ideally, the final solution will look something like this 理想情况下,最终解决方案应如下所示

// This dataset will be used for all tests that don't override it with their own annotation
@TestData('/dbunit/dataSetDefault.xml')
public class MyTests extends ProbablySomethingFromTheSpringFramework {

  @Test
  void testWithDefaultDataSet() {
    // Transaction is implicitly started here
    // My test code goes here
    // A transaction is implicitly rolled-back here    
  }

  @TestData('/dbunit/dataSetCustom.xml')
  @Test
  void testWithCustomDataSet() {
    // Same as the other test
  }
}

Obviously the parent class and the @TestData are fictitious, is there something available that provides the functionality I'm looking for? 显然,父类和@TestData是虚构的,是否有可用的东西提供我想要的功能?

This leaves the question of how to create the test DB schema. 剩下的问题是如何创建测试数据库模式。 Ideally, this would happen once before all the tests are run (by Maven). 理想情况下,这将在所有测试运行之前(由Maven执行)。 Can someone suggest how I might achieve this? 有人可以建议我如何实现这一目标吗? I imagine it involves using something to convert the JPA annotations to DDL, then something else to load that into the test database schema. 我想它涉及使用某种方法将JPA注释转换为DDL,然后使用其他方法将其加载到测试数据库模式中。

Thanks! 谢谢!

Ideally I would like to be able to: 理想情况下,我希望能够:

  • create the test DB schema (from the JPA annotated classes) once before the tests are run 在运行测试之前,一次创建测试数据库模式(从带有JPA注释的类)

At least Hibernate makes it possible to create the database from the annotated classes, I'd imagine other JPA-implementations would work too. 至少Hibernate使得可以从带注释的类创建数据库,我想其他的JPA实现也可以使用。

  • run each test method in it's own transaction which is rolled back when the test completes 在自己的事务中运行每个测试方法,该方法在测试完成时会回滚

See @TransactionConfiguration and the defaultRollback -value there, and AbstractTransactionalJUnit4SpringContextTests (there are also similar abstract classes for at least JUnit 3.8 and TestNG), take a good look at the See also -sections in the javadocs, they point to many very useful related classes and annotations. 参见@TransactionConfiguration和那里的defaultRollback -value以及AbstractTransactionalJUnit4SpringContextTests (至少在JUnit 3.8和TestNG中也有类似的抽象类),请仔细阅读javadocs中的See also-节,它们指向许多非常有用的相关类和注释。

  • specify the (DbUnit) dataset to be loaded for each test either at the per-class or per-method level. 在类或方法级别上指定要为每个测试加载的(DbUnit)数据集。 The test data should be loaded after the transaction has started so that the test data will also be rolled back when the test completes 应在事务开始后加载测试数据,以便在测试完成时也回滚测试数据

I haven't actually ever used DbUnit, but at least with JUnit, you can use @Before and @BeforeClass to run methods before each test and class, respectively (there's also @After and @AfterClass). 我实际上从未使用过DbUnit,但至少使用JUnit,您可以使用@Before@BeforeClass在每个测试和类之前分别运行方法(还有@After和@AfterClass)。 If you have a class hierarchy, the @Before/@BeforeClass -annotated methods are run in extension order (baseclass first). 如果您具有类层次结构,则@ Before / @ BeforeClass注释的方法将以扩展顺序运行(首先是基类)。 For running sql-scripts, see for example SimpleJdbcTestUtils . 有关运行sql脚本的信息,请参见例如SimpleJdbcTestUtils

  • inject Spring beans into the test class 将Spring bean注入测试类

AbstractTransactionalJUnit4SpringContextTests is ApplicationContextAware, also see @ContextConfiguration for setting things up. AbstractTransactionalJUnit4SpringContextTests是ApplicationContextAware,另请参见@ContextConfiguration进行设置。

Finally, here's a bit stripped down baseclass I use to extend my actual integration tests from (Spring 3, JUnit4, Hibernate as JPA-provider, if it matters): 最后,这是我用来扩展实际集成测试的基类的一部分(如果重要的话,从Spring 3,JUnit4,Hibernate作为JPA提供者):

    //test-context, same as normal context, except uses H2 for in-memory database and has some stuff for faking session- and request-scope
    @ContextConfiguration(locations="classpath:applicationContext-test.xml") 
    @TransactionConfiguration(transactionManager="txManager", defaultRollback=true)
    @Transactional
    public abstract class IntegrationTestBase extends AbstractTransactionalJUnit4SpringContextTests
    {
        @PersistenceContext
        protected EntityManager em; 

        @Autowired
        protected SomeService serviceAvailableToSubclasses;

        @Before
        public void beforeEachTest()
        {
            //fill database with testdata and whatever you need to, runs before each test in extending classes
        }

        @After
        public void afterEachTest()
        {
            //Do something, if you need to, or just remove this
        }

    }

Extending from this, you can use @Transactional, @Autowired etc. in your deriving classes, or derive more specific abstract test-baseclasses (I have for example IntegrationSessionTestBase and IntegrationSessionNewRequestPerTestBase for different kinds of tests, needing new sessions and/or requests per test). 从此扩展,您可以在派生类中使用@ Transactional,@ Autowired等,或派生更具体的抽象测试基类(例如,对于不同类型的测试,我具有IntegrationSessionTestBase和IntegrationSessionNewRequestPerTestBase,每个测试需要新的会话和/或请求)。

I have done that with a simple JPA (Hibernate) based app. 我已经用一个简单的基于JPA(Hibernate)的应用程序做到了。

<project
  xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>

  <groupId>com.soebes.casestudy</groupId>
  <artifactId>casestudy</artifactId>
  <packaging>jar</packaging>
  <version>0.0.1-SNAPSHOT</version>

  <name>Case Study Pizza Ordering</name>
  <url>Pizza Ordering</url>

  <properties>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    <hibernate-core-version>3.4.0.GA</hibernate-core-version>
    <database.driverClassName>com.mysql.jdbc.Driver</database.driverClassName>
    <database.url>jdbc:mysql://localhost:3306/casestudy</database.url>
    <database.dialect>org.hibernate.dialect.MySQLDialect</database.dialect>
    <database.root.user>root</database.root.user>
    <database.root.password>root</database.root.password>

    <database.user>casestudy</database.user>
    <database.password>casestudy</database.password>

    <database.database>casestudy</database.database>
  </properties>

  <build>
    <resources>
      <resource>
        <directory>${basedir}/src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>hibernate3-maven-plugin</artifactId>
        <version>2.2</version>
        <executions>
          <execution>
            <id>hibernate-create-schema</id>
            <phase>generate-test-sources</phase>
            <goals>
              <goal>hbm2ddl</goal>
            </goals>
            <configuration>
              <components>
                <component>
                  <name>hbm2ddl</name>
                  <implementation>annotationconfiguration</implementation>
                </component>
              </components>
              <componentProperties>
                <configurationfile>/src/main/resources/hibernate.cfg.xml</configurationfile>
                <jdk5>true</jdk5>
                <packagename>com.soebes.casestudy.bo</packagename>
                <console>false</console>
                <outputfilename>create.sql</outputfilename>
                <drop>false</drop>
                <create>true</create>
                <update>false</update>
                <export>false</export>
                <format>true</format>
              </componentProperties>
            </configuration>
          </execution>
          <execution>
            <id>hibernate-drop-schema</id>
            <phase>generate-test-sources</phase>
            <goals>
              <goal>hbm2ddl</goal>
            </goals>
            <configuration>
              <components>
                <component>
                  <name>hbm2ddl</name>
                  <implementation>annotationconfiguration</implementation>
                </component>
              </components>
              <componentProperties>
                <configurationfile>/src/main/resources/hibernate.cfg.xml</configurationfile>
                <jdk5>true</jdk5>
                <packagename>com.soebes.casestudy.bo</packagename>
                <console>false</console>
                <outputfilename>drop.sql</outputfilename>
                <drop>true</drop>
                <create>false</create>
                <update>false</update>
                <export>false</export>
                <format>true</format>
              </componentProperties>
            </configuration>
          </execution>
        </executions>
        <dependencies>
          <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.9</version>
          </dependency>
        </dependencies>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.8</version>
      </plugin>

     <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>sql-maven-plugin</artifactId>
        <version>1.4</version>

        <dependencies>
          <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.9</version>
          </dependency>
        </dependencies>

        <!-- common configuration shared by all executions -->
        <configuration>
          <driver>${database.driverClassName}</driver>
          <url>${database.url}</url>
          <username>${database.root.user}</username>
          <password>${database.root.password}</password>
        </configuration>
        <executions>
          <execution>
            <id>drop-database</id>
            <phase>generate-test-resources</phase>
            <goals>
              <goal>execute</goal>
            </goals>
            <configuration>
              <sqlCommand>
              DROP DATABASE IF EXISTS casestudy;
              CREATE DATABASE casestudy;
              GRANT ALL ON casestudy.* TO ${database.user} IDENTIFIED BY '${database.password}';
              </sqlCommand>
            </configuration>
          </execution>
          <execution>
            <id>create-database</id>
            <phase>generate-test-resources</phase>
            <goals>
              <goal>execute</goal>
            </goals>
            <configuration>
              <sqlCommand>
              USE casestudy;
              </sqlCommand>
              <srcFiles>
                <srcFile>${project.build.directory}/hibernate3/sql/create.sql</srcFile>
              </srcFiles>
            </configuration>
          </execution>
        </executions>
      </plugin>

    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-annotations</artifactId>
      <version>${hibernate-core-version}</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>3.3.0.SP1</version>
    </dependency>
    <dependency>
        <groupId>javassist</groupId>
        <artifactId>javassist</artifactId>
        <version>3.4.GA</version>
    </dependency>

    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>5.14.6</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.9</version>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.13</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.6.1</version>
    </dependency>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.6.1</version>
    </dependency>
  </dependencies>
</project>

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

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