Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 禁用spring testng测试方法上的事务_Java_Spring_Jpa_Transactions_Testng - Fatal编程技术网

Java 禁用spring testng测试方法上的事务

Java 禁用spring testng测试方法上的事务,java,spring,jpa,transactions,testng,Java,Spring,Jpa,Transactions,Testng,我正在与Spring和JPA一起使用TestNG。到目前为止,我使用扩展了AbstractTransactionalTestNGSpringContextTests的测试类来测试数据库。使用@TransactionConfiguration(defaultRollback=true)一切正常,我不需要担心清理。Spring在我的每个测试方法的开头创建一个默认事务,而不是回滚。这是一个非常巧妙的技巧,可以解决著名的“被认为有害的事务测试”问题 不幸的是,我需要这个类中的一个方法(一个测试)没有这个

我正在与Spring和JPA一起使用TestNG。到目前为止,我使用扩展了
AbstractTransactionalTestNGSpringContextTests
的测试类来测试数据库。使用
@TransactionConfiguration(defaultRollback=true)
一切正常,我不需要担心清理。Spring在我的每个测试方法的开头创建一个默认事务,而不是回滚。这是一个非常巧妙的技巧,可以解决著名的“被认为有害的事务测试”问题


不幸的是,我需要这个类中的一个方法(一个测试)没有这个默认事务。这是因为这个测试方法模拟批处理,我在其中有多个独立于生产的事务。我能够模拟和解决问题的唯一方法是使用
传播来配置这些内部事务。需要\u NEW
,但这是我不希望在生产代码中使用的。是否有某种方法可以为我的特定测试方法禁用Spring事务(因此我不需要在我的服务方法中使用
传播。REQUIRES\u NEW
,而是
传播。REQUIRED

我发现,通过在单独的线程中执行测试主体,可以防止Spring进行事务。因此,解决方案类似于:

    @ContextConfiguration(classes = { test.SpringTestConfigurator.class })
    @TransactionConfiguration(defaultRollback = false)
    @Slf4j
    @WebAppConfiguration
    public class DBDataTest extends AbstractTransactionalTestNGSpringContextTests {    
    /**
     * Variable to determine if some running thread has failed.
     */
    private volatile Exception threadException = null;

   @Test(enabled = true)
    public void myTest() {
        try {
            this.threadException = null;
            Runnable task = () -> {
                myTestBody();
            };
            ExecutorService executor = Executors.newFixedThreadPool(1);
            executor.submit(task);
            executor.shutdown();
            while (!executor.isTerminated()) {
                if (this.threadException != null) {
                    throw this.threadException;
                }
            }
            if (this.threadException != null) {
                throw this.threadException;
            }
        } catch (Exception e) {
            log.error("Test has failed.", e);
            Assert.fail();
        }
    }

 public void myTestBody() {
    try {
        // test body to do
    }
    catch (Exception e) {
       this.threadException = e; 
    } 
 } 
}

我知道你已经解决了你的问题,但是对于那些将来会来这里的人

不幸的是,似乎没有办法禁用使用
@Transactional
注释的现有测试内部事务

这里的IMHO Spring方法非常不灵活。但是你的问题有一个解决办法。将所需的逻辑封装在Spring
TransactionTemplate
类中就足够了。这将确保测试用例中的代码将在新事务中启动


个人建议:在我看来,最好、最灵活的方法是从一开始就放弃
@Transactional
测试,并在每次测试之前将数据库设置为已知状态。这样,Spring将以与生产中完全相同的方式管理事务。
没有怪癖,没有黑客,没有手动事务管理

我知道在单元测试中使用带有“回滚”策略的
@Transactional
是一个诱人的想法,但它有太多的陷阱。我推荐阅读这篇文章


当然,这里我并不抱怨@Transactional本身,因为它极大地简化了生产代码中的事务管理。

将该代码移动到另一个非事务性的测试类。Spring测试框架的早期版本有
@NotTransactional
注释,但该注释已被弃用并删除,以支持拆分事务性和非事务性测试。@M.Deinum不幸的是,这对我来说并不容易,因为我有一些依赖项,我不想重复代码,但是我发现在单独的线程中调用测试方法可以实现我想要的。在我看来,Spring测试事务保护只与主线程相关,但当我在单独的线程中调用测试方法体时,它将按我所希望的方式工作。如果有人有比我的解决方案更好的解决方案-请发布,否则我会将整个解决方案作为答案来写。@M.Deinum correct tip,但对于现有测试来说,IMHO Spring方法非常不灵活且耗时。未来提示:对我来说,最好、最灵活的方法是从一开始就放弃
@Transactional
,使用
TransactionTemplate
类。由于JDK 8的使用更加方便。因此,与声明式事务管理相比,您更喜欢回到手动事务管理的黑暗时代,这基本上就是您正在做的。@M.Deinum,只是澄清一下:我建议放弃
@Transactional
,让Spring以正常方式管理事务。我提到的
TransactionTemplate
只是为了解决现有问题(如OP提到的问题)。当然,若我们不回滚,那个么我们必须在每个测试用例之前或之后清理数据库。这是一种很好的方法,将在其他一些测试类中使用(我现在不想重写我的测试)。这是一种可怕且不必要的复杂代码测试方法。将多线程添加到测试中或添加手动方式来管理事务,这表明您首先做错了什么。如果您希望测试是非事务性的,那么就让它成为非事务性的。我还发现,应该使用不同的技术(普通JDBC)来验证结果,而不是使用用于持久化的相同技术,只有这样才能真正测试数据库内容。谁说JPA是在访问数据库而不是(一级或二级)缓存?@M.Deinum-Hmm,我不相信。确保JPA命中数据库的最常用方法是禁用二级缓存并让JPA正常提交事务。这样,就不需要使用不同的技术。你不同意吗?@M.Deinum将数据库设置为已知状态是“可怕的”和“不必要的复杂”吗?我觉得恰恰相反。以清理数据库的代价,我们没有怪癖,没有黑客,没有手动事务管理。测试中的代码与生产中的代码行为完全相同。测试代码线程是可怕的,不必要的复杂。因为在测试用例中引入了多线程,所以您遇到了一个难题。您现在也有测试污染您的数据库,或者您必须手动清理,最终这将在某个地方对您造成影响,因为现在的测试可能(因此)相互干扰。另外,关于禁用二级缓存,您仍然有一级缓存,您无法禁用它,但它仍然会咬到您(您与黑客一起工作)。禁用缓存时,您可能会遇到许多配置,以使您的te