使用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
就报异常,我查了下:
一人回答的是:
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,还望不吝赐教。多谢!