使用spring自带框架测试,代码如下:
package TestContext; import java.util.List; import javax.annotation.Resource; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestExecutionListeners; import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.transaction.BeforeTransaction; import org.springframework.test.context.transaction.TransactionalTestExecutionListener; import org.springframework.transaction.annotation.Transactional; import entity.User; import service.UserService; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:beans.xml") @TestExecutionListeners(TransactionalTestExecutionListener.class) @Transactional public class ListActionTest extends AbstractTransactionalJUnit4SpringContextTests{ private UserService userService; public UserService getUserService() { return userService; } @Resource public void setUserService(UserService userService) { this.userService = userService; } // @Rollback(false)默认true @Test public void test(){ /*User user = userService.getUser(50); System.out.println(user.getUname()); List<User> users = userService.getUsers(); System.out.println(users.size());*/ User user2 = new User(); user2.setUname("b"); user2.setPwd("b"); userService.add(user2); } }
运行时报错:
警告: Caught exception while allowing TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener@15975490] to process 'before' execution of test method [public void TestContext.ListActionTest.test()] for test instance [TestContext.ListActionTest@40dd3977] java.lang.IllegalStateException: Cannot start a new transaction without ending the existing transaction. at org.springframework.test.context.transaction.TransactionalTestExecutionListener.beforeTestMethod(TransactionalTestExecutionListener.java:169) at org.springframework.test.context.TestContextManager.beforeTestMethod(TestContextManager.java:265) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
注释掉下面一行注解
//@TestExecutionListeners(TransactionalTestExecutionListener.class)
运行成功。
ListActionTest的父类AbstractTransactionalJUnit4SpringContextTests已经使用的注解
@TestExecutionListeners({TransactionalTestExecutionListener.class, SqlScriptsTestExecutionListener.class})
而AbstractTransactionalJUnit4SpringContextTests的父类AbstractJUnit4SpringContextTests又使用了注解
@TestExecutionListeners({ ServletTestExecutionListener.class, DirtiesContextBeforeModesTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class })
所以这6个注解都会自动继承,不需要添加。
而至于为什么一添加
TransactionalTestExecutionListener.class
就报异常,我查了下:
http://stackoverflow.com/questions/19537775/transaction-with-transactional-and-transactionaltestexecutionlistener-what-is-th
一人回答的是:
TransactionalTestExecutionListener
is the only guy who creates transactions. It checks @Transactional
annotation presence and then opens transaction. In case on test execution listeners are specified spring uses some default test execution listeners one of which is TransactionalTestExecutionListener
, that is why it seems that listener and annotation works separately.
他提到TransactionalTestExecutionListener
检测到@Transactional会开启一个transaction。后半段我根据自己理解断了下句如下:
In case of test execution, listeners are specified spring, uses some default test execution listeners, one of which is TransactionalTestExecutionListener
, that is why it seems that listener and annotation works separately.
简单翻译下就是:当你执行测试时,如果指定了使用spring的监听器,那么会使用一些默认的监听器,而这些默认监听器中的其中一个便是TransactionalTestExecutionListener,这也就是为什么监听器和注解会分开使用的原因。
但是以上解释还是听得云里雾里的,所以我自己总结如下:
加上TransactionalTestExecutionListener
时就报异常java.lang.IllegalStateException: Cannot start a new transaction without ending the existing transaction.。原因是:
我们继承AbstractTransactionalJUnit4SpringContextTests时,已经继承了注解TransactionalTestExecutionListener
,这时再重复使用此注解,即是在原来已经开了一个transaction的基础上又重复开了个transaction.所以会报这个异常。
这一原因只是我个人的猜想,有看到此博客的兄弟,如有更好的解释和evidence,还望不吝赐教。多谢!