java Spring事务管理测试

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/971483/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 14:38:34  来源:igfitidea点击:

Spring Transaction Management Test

javaunit-testingspringtesting

提问by Roy Marco Aruta

I want to test my Dao Class using the SpringContextTests.
In my method class I extended the AbstractTransactionalJUnit4SpringContextTestsin order for my test class to integrate with JUnit4. I have also set up the configurations and made the initialization and database clean up in the @Beforeand tearDown in the @After. My test class works perfectly.

My problem was, when I run my test class and the database is filled with data, the original data was not rolled back and my database is cleared. In the @Beforemethod, I clear the database and populate data, thinking that I will be able to rollback it but its not.

Can anyone site an example that works and rollbacks information in the database.

ADDONS:
Every database manipulation in my test methods are rolled back. But the execution of super.deleteFromTables("person")in the @Beforemethod did not rollback all the previous data from the database.

Spring rollbacks all the CRUD operations but the database clean up before the transaction do not rollback.

我想使用 SpringContextTests 测试我的 Dao 类。
在我的方法类中,我扩展了AbstractTransactionalJUnit4SpringContextTests以便我的测试类与 JUnit4 集成。我还设置了配置,@Before并在@After. 我的测试班完美运行。

我的问题是,当我运行我的测试类并且数据库充满数据时,原始数据没有回滚并且我的数据库被清除。在@Before方法中,我清除数据库并填充数据,认为我将能够回滚它但它不会。

任何人都可以找到一个可以工作并回滚数据库中信息的示例。

插件:
我的测试方法中的每个数据库操作都会回滚。但执行super.deleteFromTables("person")@Before方法中并没有从数据库中回滚之前的所有数据。

Spring 回滚所有 CRUD 操作,但在事务之前清理数据库不会回滚。

采纳答案by Roy Marco Aruta

Thank you to all those who answered my question. I learned a lot from those answers but it didn't solve my problem.
I knew my test data does a transaction management and it does its job properly.
The mistake is on my part.

I forgot the lesson about database commands that when you execute a DDL statement after a DML statement, it will automatically commit the transaction. I executed a DDL after a DML by deleting all record and then ALTERthe AUTO_INCREMENTof the table where in it will cause an auto-commit and delete all records of the table permanently.

FIXING THAT SCENARIO SOLVED MY PROBLEM.

感谢所有回答我问题的人。我从这些答案中学到了很多东西,但并没有解决我的问题。
我知道我的测试数据可以进行事务管理并且可以正常工作。
错误在于我。

我忘记了数据库命令的教训,当你在一个 DML 语句之后执行一个 DDL 语句时,它会自动提交事务。我执行的DML后DDL通过删除所有记录,然后ALTERAUTO_INCREMENT表在哪里它会导致自动提交,并删除表中的所有记录永久的。

修复该场景解决了我的问题。

回答by Robert Munteanu

Possible causes:

可能的原因:

  • you're using a database/database engine which does not have proper transactions;
  • you're using multiple transaction managers and/or data sources and the proper one is not picked up;
  • you're doing your own, separate, transactions in the test class
  • 您正在使用没有正确事务的数据库/数据库引擎;
  • 您正在使用多个事务管理器和/或数据源,但没有选择正确的;
  • 你在测试类中做你自己的、单独的事务


As for an example, here's one ( top of my head, not compiled )

例如,这是一个(我的头顶,未编译)

public class DBTest extends AbstractTransactionalJUnit4SpringContextTests {

    @Autowired
    private SomeDAO _aBeanDefinedInMyContextFile;

    @Test
    public void insert_works() {
        assert _aBeanDefinedInMyContextFile.findAll() == 0;
        _aBeanDefinedInMyContextFile.save(new Bean());
        assert _aBeanDefinedInMyContextFile.findAll() == 1;
    }


}

Key points:

关键点:

  • the SomeDAOis an interface which corresponds to a bean declared in my context;
  • the bean does not have any transactional settings ( advice/programmatic), it relies on the caller being transactional - either the service in production, or the test in our situation;
  • the test does not include any transactional management code, as it's all done in the framework.
  • SomeDAO是对应于我的上下文中声明一个bean的接口;
  • bean 没有任何事务性设置(建议/程序化),它依赖于事务性的调用者 - 生产中的服务或我们情况下的测试;
  • 该测试不包括任何事务管理代码,因为它都是在框架中完成的。

回答by Pablojim

I'm not sure what is wrong with your class. Here is an extract of a class that does what you want with dbunit and spring 2.5:

我不确定你的课有什么问题。这是使用 dbunit 和 spring 2.5 执行您想要的操作的类的摘录:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
  "testContext.xml"})
@TransactionConfiguration
@Transactional
public class SampleDAOTest {

    @Autowired
    private DataSource dataSource;
    @Autowired
    private SampleDAO sampleDAO;

    @Before 
    public void onSetUpInTransaction() throws Exception {
        //Populate Test data
        IDatabaseConnection dbUnitCon = new DatabaseConnection(DataSourceUtils.getConnection(dataSource), "DATASOURCE");
            //read in from a dbunit excel file of test data
        IDataSet dataSet = new XlsDataSet(new File("src/test/resources/TestData.xls"));
        DatabaseOperation.INSERT.execute(dbUnitCon, dataSet);
    }


    @Test
    public void testGetIntermediaryOrganisation() {

        // Test getting a user
        User object = sampleDAO.getUser(99L);
        assertTrue(object.getValue);


    }
}

One of the benfits of this method is that you don't need to extend any classes. So you can still have your own hierarchy for tests.

这种方法的好处之一是您不需要扩展任何类。因此,您仍然可以拥有自己的测试层次结构。

If you really want to stick to your current method instead of using the @before annotation I thinnk you need to overide the below method and put your setup code in there.

如果你真的想坚持你当前的方法而不是使用 @before 注释,我认为你需要覆盖下面的方法并将你的设置代码放在那里。

@Override
public void onSetUpInTransaction() throws Exception {...}

Hope this helps

希望这可以帮助

回答by Michael Wiles

As far as I can tell, by looking at the Javadocs and source code for AbstractJUnit4SpringContextTests and TransactionalTestExecutionListener you need to annotate your test methods you want transactionalised with @Transactional.

据我所知,通过查看 AbstractJUnit4SpringContextTests 和 TransactionalTestExecutionListener 的 Javadoc 和源代码,您需要注释您希望使用 @Transactional 进行事务处理的测试方法。

There are also @BeforeTransaction and @AfterTransaction annotations where you can better control what runs in a transaction.

还有@BeforeTransaction 和@AfterTransaction 注释,您可以在其中更好地控制事务中运行的内容。

I suggest you create methods annotated with all these annotations, including @Before and then run the test with breakpoints at these methods. That way you can look at the stack and work out whether spring has started a transaction for you or not. If you see something like "TransactionInterceptor" in the stack then, or anything else with "Transaction" in the name, then chances are you're in a transaction.

我建议您创建用所有这些注释(包括 @Before)注释的方法,然后在这些方法上使用断点运行测试。这样您就可以查看堆栈并确定 spring 是否为您启动了事务。如果您在堆栈中看到诸如“TransactionInterceptor”之类的内容,或者名称中包含“Transaction”的任何其他内容,那么您很可能处于交易中。

回答by Michael Wiles

You're doing super.deleteFromTables in your @Before method which is within the tx. So if the tx is rolled back doesn't the deletions get rolled back also?

您正在 tx 内的 @Before 方法中执行 super.deleteFromTables。因此,如果 tx 回滚,删除操作不会也回滚吗?

回答by Confusion

Sidestepping your question, I suggest that you use a seperate database instance to run your tests against. That way, you can safely wipe it clean and have your tests initialize it as required.

回避你的问题,我建议你使用一个单独的数据库实例来运行你的测试。这样,您就可以安全地将其擦干净并让您的测试根据需要对其进行初始化。

As far as I know the Spring support classes for database testing only rollback what happens in the tests, not what happens in setup and teardown of tests.

据我所知,用于数据库测试的 Spring 支持类只回滚测试中发生的情况,而不回滚测试的设置和拆卸中发生的情况。

回答by Cuga

Agree with Confusion-- you should be running your tests against their own database schema.

同意混淆——你应该针对他们自己的数据库模式运行你的测试。

With this, you can set your hibernate properties to 'create-drop':

有了这个,你可以将你的休眠属性设置为“create-drop”:

With create-drop, the database schema will be dropped when the SessionFactory is closed explicitly.

使用 create-drop,当 SessionFactory 显式关闭时,数据库模式将被删除。

See: Optional Hibernate Config properites

请参阅:可选的 Hibernate 配置属性

Example snippet:

示例片段:

<bean id="sessionBean" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="hibernateProperties">
      <props>
        <prop key="hibernate.hbm2ddl.auto">create-drop</prop>
         ...etc

回答by Gareth Davis

While I'd agree with the guy's suggesting a deciated db for testing, there isn't any reason why using a populated db shouldn't work, both @Before and @After methods are executed within the transactional context, therefore there changes should be rolledback.

虽然我同意这个人建议使用一个 decated db 进行测试,但没有任何理由说明使用填充的 db 不起作用,@Before 和 @After 方法都是在事务上下文中执行的,因此应该进行更改回滚。

Possibles:

可能性:

  • The data setup is doing something that isn't transactional (ie DDL statements)
  • Something in your test is actually committing the transaction
  • 数据设置正在做一些非事务性的事情(即 DDL 语句)
  • 您的测试中的某些内容实际上是在提交事务

Can you post the @Before method, I'm just wondering if you are just clearing the tables or actually dropping and recreating them?

你能发布@Before 方法吗,我只是想知道你是在清理表格还是真的删除并重新创建它们?