数据库单元测试框架?

发布于 2024-11-28 01:09:29 字数 300 浏览 5 评论 0原文

在我的项目中,我使用了 spring、jpa 和 PostgreSQL DB, 我在数据库中有很多表,我需要对所有表进行单元测试。

是否有任何框架在每次测试完成后回滚所有事务,以便每个测试都将有新鲜/相同的数据库数据进行测试。这样在所有测试执行之后,数据库模式的数据将保持原样。

对此有何建议?

我对 DBUnit 有一些想法,但我需要为每个测试的每个输入数据编写 .xml 文件,并且需要在 setup() 中插入数据并在 TeaDown() 中清除/删除数据,但似乎没有更好的策略大部头书。

任何建议表示赞赏。 谢谢。

In my project, I've used spring, jpa with PostgreSQL DB,
I've lots of table in DB and I need to have Unit testing of all of them.

Is there any framework which just rollback all the transactions after each test finished so every test will have fresh/same DB data to Test. And this way after all Test executions, data of DB schema would be as it is.

Any suggestion for this?

I've some idea of DBUnit but in that I need to write .xml files for every input data for every test and need to insert data in setup() and clear/remove data in tearDown(), but doesn't seems better strategy to me.

Any suggestion is appreciated.
Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

小梨窩很甜 2024-12-05 01:09:29

正如@Ryan所指出的......Spring参考的 测试部分应查阅手册

一些启动技巧...

我们已经使用 Spring 的 AbstractTransactionalJUnit4SpringContextTests 处理了这个问题。

例如,我们定义一个抽象超类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:WebContent/WEB-INF/testconfig/test-web-application-config.xml")
@TransactionConfiguration()
@Transactional
public abstract class OurAbstractTransactionalSpringContextTest extends AbstractTransactionalJUnit4SpringContextTests {
}

然后将需要附加上下文的各个子类定义为:

@ContextConfiguration("classpath:path/to/config/ConfigForTestCase.xml")
public class TestOurFunction extends OurAbstractTransactionalSpringContextTest {
    @Test
    public void testOurMethod() {
    }

}

请注意:

  1. 并非所有测试类都需要附加上下文,请跳过特定子类上的@ContextConfiguration
  2. 我们通过 ant 执行并在 junit 任务上使用 forkmode="perBatch" 属性。这可确保所有测试都使用相同的上下文配置运行(无需为每个测试重新加载 Spring 上下文)。您可以使用 @DirtiesContext 来指示应在方法/类之后刷新上下文。
  3. 使用@Test注释标记每个方法。 Spring 框架不会使用 Junit 的 public void testXXX() 约定来选取方法。

As @Ryan indicates .... the Testing section of the Spring Reference manual should be consulted.

Some startup tips...

We've handled this using Spring's AbstractTransactionalJUnit4SpringContextTests.

For example, we define an abstract superclass:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:WebContent/WEB-INF/testconfig/test-web-application-config.xml")
@TransactionConfiguration()
@Transactional
public abstract class OurAbstractTransactionalSpringContextTest extends AbstractTransactionalJUnit4SpringContextTests {
}

And then individual subclasses which need additional context get defined as:

@ContextConfiguration("classpath:path/to/config/ConfigForTestCase.xml")
public class TestOurFunction extends OurAbstractTransactionalSpringContextTest {
    @Test
    public void testOurMethod() {
    }

}

Note that:

  1. Not all test classes need additional context for them, skip the @ContextConfiguration on the particular subclass.
  2. We execute via ant and use the forkmode="perBatch" attribute on the junit task. That ensures all tests run with the same context configuration (saves from reloading the Spring context for each test). You can use the @DirtiesContext to indicate that the context should be refreshed after a method/class.
  3. mark each method with the @Test annotation. The Spring framework doesn't pick up methods using Junit's public void testXXX() convention.
猫卆 2024-12-05 01:09:29

是否有任何框架可以在每次测试完成后回滚所有事务,以便每个测试都将有新鲜/相同的数据库数据进行测试。这样在所有测试执行之后,数据库模式的数据将保持原样。

来自我的其他答案之前发布的天,是的,这可以使用 DbUnit 实现。 (根据您的编辑,您不需要这个;我的答案的后续部分说明了我使用 DbUnit 的原因以及何时不使用它)。

以下代码片段演示了如何执行每个测试的设置:

@Before
public void setUp() throws Exception
{
    logger.info("Performing the setup of test {}", testName.getMethodName());
    IDatabaseConnection connection = null;
    try
    {
        connection = getConnection();
        IDataSet dataSet = getDataSet();
        //The following line cleans up all DbUnit recognized tables and inserts and test data before every test.
        DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
    }
    finally
    {
        // Closes the connection as the persistence layer gets it's connection from elsewhere
        connection.close();
    }
}

private IDatabaseConnection getConnection() throws Exception
{
    @SuppressWarnings({ "rawtypes", "unused" })
    Class driverClass = Class.forName("org.apache.derby.jdbc.ClientDriver");
    Connection jdbcConnection = DriverManager.getConnection(jdbcURL, "XXX",
            "YYY");
    IDatabaseConnection databaseConnection = new DatabaseConnection(jdbcConnection);
    return databaseConnection;
}

private IDataSet getDataSet() throws Exception
{
    ClassLoader classLoader = this.getClass().getClassLoader();
    return new FlatXmlDataSetBuilder().build(classLoader.getResourceAsStream("database-test-setup.xml"));
}

database-test-setup.xml 文件包含将为每个测试插入数据库的数据。在 setup 方法中使用 DatabaseOperation.CLEAN_INSERT 可确保清除文件中指定的所有表(通过删除所有行),然后插入测试数据文件中的指定数据。

避免 DbUnit

我使用上述方法专门在每次测试开始之前清除序列,因为应用程序使用 JPA 提供程序在单独的事务中更新序列。如果您的应用程序没有执行类似的操作,那么您可以在 setup() 方法中简单地启动一个事务,并在测试后在拆卸时发出回滚。如果我的应用程序不使用序列(并且如果我不想重置它们),那么我的设置例程将非常简单:

@Before
public void setUp() throws Exception
{
    logger.info("Performing the setup of test {}", testName.getMethodName());
    // emf is created in the @BeforeClass annotated method
    em = emf.createEntityManager();
    // Starts the transaction before every test
    em.getTransaction.begin();
}

@After
public void tearDown() throws Exception
{
    logger.info("Performing the teardown of test {}", testName.getMethodName());
    if (em != null)
    {
        // Rolls back the transaction after every test
        em.getTransaction().rollback();
        em.close();
    }
}

此外,我使用 dbdeploy 与 Maven 一起使用,但这主要是为了使测试数据库与版本化数据模型保持最新。

Is there any framework which just rollback all the transactions after each test finished so every test will have fresh/same DB data to Test. And this way after all Test executions, data of DB schema would be as it is.

From my other answer posted earlier in the day, yes, this is possible using DbUnit. (Based on your edit, you don't need this; the subsequent section of my answer addresses why I use DbUnit, and when I wouldn't use it).

The following code snippet demonstrates how the setup of every test is performed:

@Before
public void setUp() throws Exception
{
    logger.info("Performing the setup of test {}", testName.getMethodName());
    IDatabaseConnection connection = null;
    try
    {
        connection = getConnection();
        IDataSet dataSet = getDataSet();
        //The following line cleans up all DbUnit recognized tables and inserts and test data before every test.
        DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet);
    }
    finally
    {
        // Closes the connection as the persistence layer gets it's connection from elsewhere
        connection.close();
    }
}

private IDatabaseConnection getConnection() throws Exception
{
    @SuppressWarnings({ "rawtypes", "unused" })
    Class driverClass = Class.forName("org.apache.derby.jdbc.ClientDriver");
    Connection jdbcConnection = DriverManager.getConnection(jdbcURL, "XXX",
            "YYY");
    IDatabaseConnection databaseConnection = new DatabaseConnection(jdbcConnection);
    return databaseConnection;
}

private IDataSet getDataSet() throws Exception
{
    ClassLoader classLoader = this.getClass().getClassLoader();
    return new FlatXmlDataSetBuilder().build(classLoader.getResourceAsStream("database-test-setup.xml"));
}

The database-test-setup.xml file contains the data that will be inserted into the database for every test. The use of DatabaseOperation.CLEAN_INSERT in the setup method ensures that all the tables specified in the file will be cleared (by a delete of all rows) followed by an insert of the specified data in the test data file.

Avoiding DbUnit

I use the above approach specifically to clear out sequences before the start of every test, as the application uses a JPA provider which updates the sequences in a separate transaction. If your application is not doing anything like that, then you can afford to simply start a transaction in your setup() method and issue a rollback on teardown after the test. If my application didn't use sequences (and if I didn't desire to reset them), then my setup routine would have been as simple as:

@Before
public void setUp() throws Exception
{
    logger.info("Performing the setup of test {}", testName.getMethodName());
    // emf is created in the @BeforeClass annotated method
    em = emf.createEntityManager();
    // Starts the transaction before every test
    em.getTransaction.begin();
}

@After
public void tearDown() throws Exception
{
    logger.info("Performing the teardown of test {}", testName.getMethodName());
    if (em != null)
    {
        // Rolls back the transaction after every test
        em.getTransaction().rollback();
        em.close();
    }
}

Also, I use dbdeploy with Maven, but that is primarily for keeping the test database up to date with the versioned data model.

噩梦成真你也成魔 2024-12-05 01:09:29

我是按照以下方式处理的。

当项目处于测试模式时。我使用引导数据来使用 dbdeploy 进行测试
您可以断言的固定数据。并直接使用dao来测试应用程序的DAO和DB层。

希望它对

更新

有所帮助,例如您的系统中有一个名为Person的实体,现在您可以在其上测试基本的CRUD操作。

  • 运行引导数据脚本来加载数据,
  • 从数据库中检索所有人员并对其进行断言。同样,查看所有 CRUD

来回滚您可以标记的事务,

@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)

这样它将回滚数据库内容

I'd handled it following ways.

When the project is in test mode. I'd used bootstraping data to to test using dbdeploy
Fixed data that you can assert on. and use the dao directly to test the DAO and DB layer of your application.

Hope it helps

Update

for example there is an entity called Person in your system, now what you can test on this is basic CRUD operations.

  • Run bootstraping data scripts to laod the data
  • retrieve all the persons from DB and assert on it. like wise see all the CRUD

to rollback the transaction you can mark

@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)

so it will rollback the DB stuff

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文