交易在junit中不起作用?

时间:2012-11-23 08:05:15

标签: spring junit transactions

这里有很多关于Transactions和JUnit的问题。但请在阅读之前仔细阅读,因为我找不到任何有同样问题的人。

我有一个商务方法,注释@Transactional。在这种方法中,如果出现某些特殊情况,我将进行编程回滚。 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

现在让我们不要讨论编程回滚是好还是坏。让我们接受它,并接受它留在那里并使用它。

如果我启动我的应用程序并以老式的方式测试这种商务方法,那么一切都很完美。什么东西应该被回滚,它被回滚,当一切都好的时候,一切都好。而且我也在没有@Transactional的情况下进行了测试,只是为了看到没有任何东西可以回滚,即使它应该。 一切都按计划进行。

但我遇到的问题是JUnit。目前我有2个JUnit测试此方法。 1应该失败(并触发编程回滚)和一个没有回滚的成功。

我尝试了很多不同的Junit类设置。目前它看起来像这样:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:springTestContext.xml", "classpath:springTestContext-dao.xml"})
@TransactionConfiguration(transactionManager = "txManager")
public class MyManagerTest extends AbstractTransactionalJUnit4SpringContextTests {
    @Mock
    private ProductDao productDao;

    @InjectMocks
    MyManager myManager = new MyManagerImpl();

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testUnParsableXml() {
        String xml = "adlsfas";
        Response response = myManager.processXMLContent(xml);
        assertFalse(response.isSuccess());
        System.out.println(response.getResponse());
    }

}
@Service("myManager")
public class MyManagerImpl extends BaseManager implements MyManager {
    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public Response processXMLContent(String xml) {
       /* NB. Extremly simplified version.... */
       Response response = new Response();
       try {
            parseXml(); // just dummy sample. Its actually parsing xml
            response.setSuccess(true)
       catch(SAXException e) {
           TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
           response.setSuccess(false);
       }
       return response;
    }
}

springTestContext具有<tx:annotation-driven注释,dao-context具有transactionmanager,entityfactory和数据源。 可能甚至不需要那些?因为这个测试在db中绝对没有任何关系。我想要测试的是,如果失败,则在事务中完成编程回滚。

但我添加它们的原因是因为我试图在这里获得帮助的错误。每当在商务方法中调用programaticly rollback时,我总是会得到这个错误(仅适用于junit测试,否则完全正常工作):

org.springframework.transaction.NoTransactionException: No transaction aspect-managed TransactionStatus in scope

所以我的问题是:我做错了什么。如何让我的商务方法进行交易? 然后作为奖励问题,我如何测试在事务中调用回滚?

感谢您的时间和帮助!

3 个答案:

答案 0 :(得分:2)

您必须使用 AbstractTraUnactionalJUnit4SpringContextTests 设置的 SpringJUnit4ClassRunner 运行测试,但是您已使用 MockitoJunitRunner 覆盖它。只需删除测试顶部的 RunWith 即可。

答案 1 :(得分:2)

您创建MyManager类MyManager myManager = new MyManagerImpl();的新实例,而不是使用上下文中的实际bean

@Resource(name="myContext")
MyManager myManager;

显然,no proxy is being created和你所指的MyManager实例甚至不是Spring bean,因为它不是在DI容器中创建的。

对于测试类中的@Transactional注释方法,我相信它们是用TransactionalTestExecutionListener执行的(因此机制与容器中的机制略有不同),但我认为这不应该影响容器本身的事务包装器 - 如果需要,请参阅beforeTestMethod和afterTestMethod以检查PlatformTransactionManager的操作。

来自documentation

  

在TestContext框架中,事务由管理   TransactionalTestExecutionListener,通过配置   默认情况下@TestExecutionListeners注释,即使您没有   在测试类上显式声明@TestExecutionListeners。至   启用对事务的支持,但是,您必须提供   PlatformTransactionManager bean在应用程序上下文中加载   @ContextConfiguration语义。此外,您必须申报   @Transactional在类或方法级别。

所以我认为运行测试clases的@Transactional注释方法和实际bean之间没有那么大差别(当然,测试类的默认回滚标志除外) - TransactionAspectSupport和TransactionalTestExecutionListener只调用底层PlatformTransactionManager的方法。

P.S。至于你的集成测试,你不清楚你正在尝试模拟bean(ProductDao和MyManager) - 当我们用Spring进行集成测试时,我们测试真实bean如何交互在一起,只模拟容器外部的依赖项(例如,使用MockServletContext而不是绑定到真实的Web服务器)或用轻量级/嵌入式服务器替换重量级/生产级服务器上的依赖项 - 这是现实条件,便利性和测试执行速度之间的平衡。 / p>

答案 2 :(得分:0)

如果只想通过此测试,则可以在方法上添加@Test(expected = NoTransactionException.class)。