spring提供了各种mock工具
JNDI
org.springframework.mock.jndi包下面
Servlet API
org.springframework.mock.web包下面。
Portlet API
org.springframework.mock.web.portlet包下面
公用测试帮助类
org.springframework.test.util,用于给一些特殊的变量,如hibernate的configuration配置属性(他们的属性都是私有的)。如类ReflectionTestUtils。
springmvc
org.springframework.test.web包得ModelAndViewAssert
测试springmvc需要用到
ModelAndViewAssert
MockHttpServletRequest
MockHttpSession
org.springframework.mock.web下面的其他类
package com.superschool.test;
import javax.annotation.Resource;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.GenericXmlContextLoader;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.web.ModelAndViewAssert;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
import com.superschool.action.MyAction;
import com.superschool.service.IMy;
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:/com/superschool/resource/spring/context/application/applicationContext.xml",
"classpath:/com/superschool/resource/spring/context/web/superschool-servlet.xml" }, loader = GenericXmlContextLoader.class)
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
@Transactional
public class TestMy {
@Autowired
private IMy test;
@Autowired
private MyAction action;
@Resource(type = AnnotationMethodHandlerAdapter.class)
private HandlerAdapter handlerAdapter;
@BeforeTransaction
public void beforeTransaction() {
System.out.println("事物开始了");
}
@Test
@Rollback(false)
public void testMy() {
Assert.assertTrue(test.add());
}
@Test
public void testMyAction() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("get", "/");
MockHttpServletResponse response = new MockHttpServletResponse();
ModelAndView mv = handlerAdapter.handle(request, response, action);
ModelAndViewAssert.assertViewName(mv, "index");
}
}
集成测试
这个时候我们更多的希望不是将测试部署到服务器或者实际环境中。
如SPRING的ioc。
orm中间件。
1.上下文
spring提供的上下文对象ApplicationContext的mock。
ApplicationContext只会mock一次。
2.对于事物管理
我们可能会对测试数据进行修改操作,而修改操作可能会造成下一次的测试失败。而SPRING则提供了完美的事物管理,可以在我们结束测试后,恢复数据。
3.集成测试
spring提供了几个方便的类来书写集成测试。
4.jdbc测试
org.springframework.test.jdbc.SimpleJdbcTestUtils是对jdbc的支持。
提供的注解
@ContextConfiguration
定义类级别的注解,用于设置如何加载mock applicationcontext。
package com.superschool.test.demo;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.support.GenericXmlContextLoader;
@ContextConfiguration(locations = { "classpath:com/superschool/resource/spring/context/application/applicationContext.xml" }, loader = GenericXmlContextLoader.class)
public class TestA {
@Test
public void testMy() {
Assert.assertTrue(true);
}
}
@DirtiesContext
表示测试完成后会破坏applicationContext。需要重新加载applicationContext。
mode属性可以设置为AFTER_CLASS表示当前类结束后,applicationContext需要重新mock。
AFTER_EACH_TEST_METHOD每个测试方法结束后都需要重新mock。
如果生命在一个方法上面,那么表示当前方法结束后,需要重新mock。
package com.superschool.test.demo;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.support.GenericXmlContextLoader;
@ContextConfiguration(locations = { "classpath:com/superschool/resource/spring/context/application/applicationContext.xml" }, loader = GenericXmlContextLoader.class)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class TestA {
@DirtiesContext
@Test
public void testMy() {
Assert.assertTrue(true);
}
}
@TestExecutionListeners
定义类级别的元数据配置。改注解应该同时配置一个TestContextManager。一般和ContextConfiguration注解同时使用,ContextConfiguration mock出来的TestContxt就是TestContextManager。
package com.superschool.test.demo;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.GenericXmlContextLoader;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
@ContextConfiguration(locations = { "classpath:com/superschool/resource/spring/context/application/applicationContext.xml" }, loader = GenericXmlContextLoader.class)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TestExecutionListeners({ TransactionalTestExecutionListener.class })
public class TestA {
@DirtiesContext
@Test
public void testMy() {
Assert.assertTrue(true);
}
}
@TransactionConfiguration
事物配置
transactionManager属性设置一个bean name,用来获取
PlatformTransactionManager 类型的bean。默认值是transactionManager。这个值应和tx:annotation-driven mode="proxy"
transaction-manager="transactionManager" />这里的相同。
defaultRollback 默认回滚属性。true表示测试结束恢复数据。
通常和ContextConfiguration同时存在。
package com.superschool.test.demo;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.GenericXmlContextLoader;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
@ContextConfiguration(locations = { "classpath:com/superschool/resource/spring/context/application/applicationContext.xml" }, loader = GenericXmlContextLoader.class)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TestExecutionListeners({ TransactionalTestExecutionListener.class })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class TestA {
@DirtiesContext
@Test
@Rollback(false)
public void testMy() {
Assert.assertTrue(true);
}
}
@BeforeTransaction表示在事物开始前运行,需要@Transactional注解才能有效
package com.superschool.test.demo;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.GenericXmlContextLoader;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
@ContextConfiguration(locations = { "classpath:com/superschool/resource/spring/context/application/applicationContext.xml" }, loader = GenericXmlContextLoader.class)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TestExecutionListeners({ TransactionalTestExecutionListener.class })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class TestA {
@BeforeTransaction
public void beforeTransaction() {
System.out.println("事物开始了");
}
@DirtiesContext
@Test
@Rollback(false)
public void testMy() {
Assert.assertTrue(true);
}
}
@AfterTransaction
类似
@NotTransactional
表示这个方法必须运行在一个非事物上下文下面。已经过时。
@Rollback
测试结束后是否回滚
配置在方法上面。
package com.superschool.test.demo;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.GenericXmlContextLoader;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
@ContextConfiguration(locations = { "classpath:com/superschool/resource/spring/context/application/applicationContext.xml" }, loader = GenericXmlContextLoader.class)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TestExecutionListeners({ TransactionalTestExecutionListener.class })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class TestA {
@DirtiesContext
@Test
@Rollback(false)
public void testMy() {
Assert.assertTrue(true);
}
}
一个例子
package com.superschool.test.demo;
import javax.annotation.Resource;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionConfiguration;
import com.superschool.service.TestI;
@RunWith(value = SpringJUnit4ClassRunner.class)
//注意主力的classpath:后面以/开头,因为不以/开通,spring就会相对当前测试类所在的包往下递归找
@ContextConfiguration(locations = {
"classpath:/com/superschool/resource/spring/context/application/applicationContext.xml",
"classpath:/com/superschool/resource/spring/context/web/superschool-servlet.xml" })
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class TestA {
@Resource
private TestI test;
@BeforeTransaction
public void beforeTransaction() {
System.out.println("事物开始了");
}
@DirtiesContext
@Test
@Rollback(false)
public void testMy() {
test.test();
Assert.assertTrue(true);
}
}
@IfProfileValue
当某个属性(properties形式的)存在或者给它指定一个值,只有值为这个值的时候才会执行这个测试。
package com.superschool.test.demo;
import javax.annotation.Resource;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.IfProfileValue;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionConfiguration;
import com.superschool.service.TestI;
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:/com/superschool/resource/spring/context/application/applicationContext.xml",
"classpath:/com/superschool/resource/spring/context/web/superschool-servlet.xml" })
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class TestA {
@Resource
private TestI test;
@BeforeTransaction
public void beforeTransaction() {
System.out.println("事物开始了");
}
@DirtiesContext
@Test
@Rollback(false)
@IfProfileValue(name = "java.vendor")
public void testMy() {
Assert.assertTrue(test.test());
}
@DirtiesContext
@Test
@Rollback(false)
@IfProfileValue(name = "java.vendor", value = "xxxxxx")
public void testMy1() {
Assert.assertTrue(test.test());
}
}
上面的例子定义了两个例子,一个只要定义了java.vendor属性就会执行。
一个是只有当属性java.vendor值等于xxxxxx才会执行。
也可以以组的方式存在
@IfProfileValue(name="test-groups", values={"unit-tests", "integration-tests"})
@Test
public void testProcessWhichRunsForUnitOrIntegrationTestGroups() {
// some logic that should run only for unit and integration test groups
}
只有有一个满足就可以了。
@ProfileValueSourceConfiguration
类级别的注解,指定IfProfileValue读取属性的实现类。默认是SystemProfileValueSource
@ExpectedException
预期测试将会抛出的异常。如果异常没有抛出或者类型不一样,将会测试失败。
@ExpectedException(SomeBusinessException.class)
public void testProcessRainyDayScenario() {
// some logic that should result in an Exception being thrown
}
@Timed
预期执行最大的时间。
spring的@Timed和junit的Timeout 区别是spring超时也不会立即停止,而是等待测试结束,计算总时间。包括重复的时间。
@Repeat
表示改测试将会重复执行N次
package com.superschool.test.demo;
import javax.annotation.Resource;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.Repeat;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionConfiguration;
import com.superschool.service.TestI;
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:/com/superschool/resource/spring/context/application/applicationContext.xml",
"classpath:/com/superschool/resource/spring/context/web/superschool-servlet.xml" })
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class TestA {
@Resource
private TestI test;
@BeforeTransaction
public void beforeTransaction() {
System.out.println("事物开始了");
}
@Repeat(10)
@DirtiesContext
@Test
@Rollback(false)
public void testMy() {
Assert.assertTrue(test.test());
}
}
另外还支持spring的其他所有注解。
@Autowired
• @Qualifier
• @Resource (javax.annotation) if JSR-250 is present
• @Inject (javax.inject) if JSR-330 is present
• @Named (javax.inject) if JSR-330 is present
• @Provider (javax.inject) if JSR-330 is present
• @PersistenceContext (javax.persistence) if JPA is present
• @PersistenceUnit (javax.persistence) if JPA is present
• @Required
• @Transactional
TestContextManager是测试的入口。
TestExecutionListener定义了监视时间的API
上下文的管理一般不会去理会,但是有时候需要访问的话
可以
package com.superschool.test.demo;
import javax.annotation.Resource;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.Repeat;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.GenericXmlContextLoader;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionConfiguration;
import com.superschool.service.TestI;
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:/com/superschool/resource/spring/context/application/applicationContext.xml",
"classpath:/com/superschool/resource/spring/context/web/superschool-servlet.xml" }, loader = GenericXmlContextLoader.class)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class TestA {
@Resource
private TestI test;
@Autowired
private ApplicationContext applicationContext;
@BeforeTransaction
public void beforeTransaction() {
System.out.println("事物开始了");
}
@Repeat(10)
@DirtiesContext
@Test
@Rollback(false)
public void testMy() {
Assert.assertTrue(test.test());
}
}
@ContextConfiguration(locations = {
"classpath:/com/superschool/resource/spring/context/application/applicationContext.xml",
"classpath:/com/superschool/resource/spring/context/web/superschool-servlet.xml" }, loader = GenericXmlContextLoader.class)
这里的loader=GenericXmlContextLoader.class可以不需要,因为它就是默认加载器。
默认情况下会加载当前包下面的MyTest-context.xml
如你的测试类是com.example.MyTest
那么会加载classpath:/com/example/MyTest-context.xml
另外如果要自己写classpath应该是classpath:/xx/xxxx/xxxx而不是classpath:xx/xxxx/xxxx
。因为如果写classpath:/xx/xxxx/xxxx它会在当前包下面查找xx.xxxx子包的xxxx文件
正常情况下ApplicationContext只加载一次,这个测试类之后的测试都重用一个applicationcontext。
inheritLocations属性 表示从父类加载。
默认是true
@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/base-context.xml" in the root of the classpath
@ContextConfiguration("/base-context.xml")
public class BaseTest {
// class body...
}
// ApplicationContext will be loaded from "/base-context.xml" and "/extended-context.xml"
// in the root of the classpath
@ContextConfiguration("/extended-context.xml")
public class ExtendedTest extends BaseTest {
// class body...
}
默认情况下会自动配置一个DependencyInjectionTestExecutionListener的TestExecutionListeners。它会自动注入属性。
如
@RunWith(SpringJUnit4ClassRunner.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration("daos.xml")
public final class HibernateTitleDaoTests {
// this instance will be dependency injected by type
@Autowired
private HibernateTitleDao titleDao;
public void testLoadTitle() throws Exception {
Title title = this.titleDao.loadTitle(new Long(10));
assertNotNull(title);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration("daos.xml")
public final class HibernateTitleDaoTests {
// this instance will be dependency injected by type
private HibernateTitleDao titleDao;
@Autowired
public void setTitleDao(HibernateTitleDao titleDao) {
this.titleDao = titleDao;
}
public void testLoadTitle() throws Exception {
Title title = this.titleDao.loadTitle(new Long(10));
assertNotNull(title);
}
}
这种方式完全符合spring的注入规则。包括Resource注解。Qualifier注解
默认情况下会自动配置一个TransactionalTestExecutionListener。但是你必须设置的PlatformTransactionManager bean
如
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
另外还要加入
@Transactional
测试支持类
org.springframework.test.context.junit4包
运行器
@RunWith(SpringJUnit4ClassRunner.class)
会自动加载配置
JNDI
org.springframework.mock.jndi包下面
Servlet API
org.springframework.mock.web包下面。
Portlet API
org.springframework.mock.web.portlet包下面
公用测试帮助类
org.springframework.test.util,用于给一些特殊的变量,如hibernate的configuration配置属性(他们的属性都是私有的)。如类ReflectionTestUtils。
springmvc
org.springframework.test.web包得ModelAndViewAssert
测试springmvc需要用到
ModelAndViewAssert
MockHttpServletRequest
MockHttpSession
org.springframework.mock.web下面的其他类
package com.superschool.test;
import javax.annotation.Resource;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.GenericXmlContextLoader;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.web.ModelAndViewAssert;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
import com.superschool.action.MyAction;
import com.superschool.service.IMy;
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:/com/superschool/resource/spring/context/application/applicationContext.xml",
"classpath:/com/superschool/resource/spring/context/web/superschool-servlet.xml" }, loader = GenericXmlContextLoader.class)
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
@Transactional
public class TestMy {
@Autowired
private IMy test;
@Autowired
private MyAction action;
@Resource(type = AnnotationMethodHandlerAdapter.class)
private HandlerAdapter handlerAdapter;
@BeforeTransaction
public void beforeTransaction() {
System.out.println("事物开始了");
}
@Test
@Rollback(false)
public void testMy() {
Assert.assertTrue(test.add());
}
@Test
public void testMyAction() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("get", "/");
MockHttpServletResponse response = new MockHttpServletResponse();
ModelAndView mv = handlerAdapter.handle(request, response, action);
ModelAndViewAssert.assertViewName(mv, "index");
}
}
集成测试
这个时候我们更多的希望不是将测试部署到服务器或者实际环境中。
如SPRING的ioc。
orm中间件。
1.上下文
spring提供的上下文对象ApplicationContext的mock。
ApplicationContext只会mock一次。
2.对于事物管理
我们可能会对测试数据进行修改操作,而修改操作可能会造成下一次的测试失败。而SPRING则提供了完美的事物管理,可以在我们结束测试后,恢复数据。
3.集成测试
spring提供了几个方便的类来书写集成测试。
4.jdbc测试
org.springframework.test.jdbc.SimpleJdbcTestUtils是对jdbc的支持。
提供的注解
@ContextConfiguration
定义类级别的注解,用于设置如何加载mock applicationcontext。
package com.superschool.test.demo;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.support.GenericXmlContextLoader;
@ContextConfiguration(locations = { "classpath:com/superschool/resource/spring/context/application/applicationContext.xml" }, loader = GenericXmlContextLoader.class)
public class TestA {
@Test
public void testMy() {
Assert.assertTrue(true);
}
}
@DirtiesContext
表示测试完成后会破坏applicationContext。需要重新加载applicationContext。
mode属性可以设置为AFTER_CLASS表示当前类结束后,applicationContext需要重新mock。
AFTER_EACH_TEST_METHOD每个测试方法结束后都需要重新mock。
如果生命在一个方法上面,那么表示当前方法结束后,需要重新mock。
package com.superschool.test.demo;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.support.GenericXmlContextLoader;
@ContextConfiguration(locations = { "classpath:com/superschool/resource/spring/context/application/applicationContext.xml" }, loader = GenericXmlContextLoader.class)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
public class TestA {
@DirtiesContext
@Test
public void testMy() {
Assert.assertTrue(true);
}
}
@TestExecutionListeners
定义类级别的元数据配置。改注解应该同时配置一个TestContextManager。一般和ContextConfiguration注解同时使用,ContextConfiguration mock出来的TestContxt就是TestContextManager。
package com.superschool.test.demo;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.GenericXmlContextLoader;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
@ContextConfiguration(locations = { "classpath:com/superschool/resource/spring/context/application/applicationContext.xml" }, loader = GenericXmlContextLoader.class)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TestExecutionListeners({ TransactionalTestExecutionListener.class })
public class TestA {
@DirtiesContext
@Test
public void testMy() {
Assert.assertTrue(true);
}
}
@TransactionConfiguration
事物配置
transactionManager属性设置一个bean name,用来获取
PlatformTransactionManager 类型的bean。默认值是transactionManager。这个值应和tx:annotation-driven mode="proxy"
transaction-manager="transactionManager" />这里的相同。
defaultRollback 默认回滚属性。true表示测试结束恢复数据。
通常和ContextConfiguration同时存在。
package com.superschool.test.demo;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.GenericXmlContextLoader;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
@ContextConfiguration(locations = { "classpath:com/superschool/resource/spring/context/application/applicationContext.xml" }, loader = GenericXmlContextLoader.class)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TestExecutionListeners({ TransactionalTestExecutionListener.class })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class TestA {
@DirtiesContext
@Test
@Rollback(false)
public void testMy() {
Assert.assertTrue(true);
}
}
@BeforeTransaction表示在事物开始前运行,需要@Transactional注解才能有效
package com.superschool.test.demo;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.GenericXmlContextLoader;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
@ContextConfiguration(locations = { "classpath:com/superschool/resource/spring/context/application/applicationContext.xml" }, loader = GenericXmlContextLoader.class)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TestExecutionListeners({ TransactionalTestExecutionListener.class })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class TestA {
@BeforeTransaction
public void beforeTransaction() {
System.out.println("事物开始了");
}
@DirtiesContext
@Test
@Rollback(false)
public void testMy() {
Assert.assertTrue(true);
}
}
@AfterTransaction
类似
@NotTransactional
表示这个方法必须运行在一个非事物上下文下面。已经过时。
@Rollback
测试结束后是否回滚
配置在方法上面。
package com.superschool.test.demo;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.support.GenericXmlContextLoader;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
@ContextConfiguration(locations = { "classpath:com/superschool/resource/spring/context/application/applicationContext.xml" }, loader = GenericXmlContextLoader.class)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TestExecutionListeners({ TransactionalTestExecutionListener.class })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class TestA {
@DirtiesContext
@Test
@Rollback(false)
public void testMy() {
Assert.assertTrue(true);
}
}
一个例子
package com.superschool.test.demo;
import javax.annotation.Resource;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionConfiguration;
import com.superschool.service.TestI;
@RunWith(value = SpringJUnit4ClassRunner.class)
//注意主力的classpath:后面以/开头,因为不以/开通,spring就会相对当前测试类所在的包往下递归找
@ContextConfiguration(locations = {
"classpath:/com/superschool/resource/spring/context/application/applicationContext.xml",
"classpath:/com/superschool/resource/spring/context/web/superschool-servlet.xml" })
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class TestA {
@Resource
private TestI test;
@BeforeTransaction
public void beforeTransaction() {
System.out.println("事物开始了");
}
@DirtiesContext
@Test
@Rollback(false)
public void testMy() {
test.test();
Assert.assertTrue(true);
}
}
@IfProfileValue
当某个属性(properties形式的)存在或者给它指定一个值,只有值为这个值的时候才会执行这个测试。
package com.superschool.test.demo;
import javax.annotation.Resource;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.IfProfileValue;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionConfiguration;
import com.superschool.service.TestI;
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:/com/superschool/resource/spring/context/application/applicationContext.xml",
"classpath:/com/superschool/resource/spring/context/web/superschool-servlet.xml" })
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class TestA {
@Resource
private TestI test;
@BeforeTransaction
public void beforeTransaction() {
System.out.println("事物开始了");
}
@DirtiesContext
@Test
@Rollback(false)
@IfProfileValue(name = "java.vendor")
public void testMy() {
Assert.assertTrue(test.test());
}
@DirtiesContext
@Test
@Rollback(false)
@IfProfileValue(name = "java.vendor", value = "xxxxxx")
public void testMy1() {
Assert.assertTrue(test.test());
}
}
上面的例子定义了两个例子,一个只要定义了java.vendor属性就会执行。
一个是只有当属性java.vendor值等于xxxxxx才会执行。
也可以以组的方式存在
@IfProfileValue(name="test-groups", values={"unit-tests", "integration-tests"})
@Test
public void testProcessWhichRunsForUnitOrIntegrationTestGroups() {
// some logic that should run only for unit and integration test groups
}
只有有一个满足就可以了。
@ProfileValueSourceConfiguration
类级别的注解,指定IfProfileValue读取属性的实现类。默认是SystemProfileValueSource
@ExpectedException
预期测试将会抛出的异常。如果异常没有抛出或者类型不一样,将会测试失败。
@ExpectedException(SomeBusinessException.class)
public void testProcessRainyDayScenario() {
// some logic that should result in an Exception being thrown
}
@Timed
预期执行最大的时间。
spring的@Timed和junit的Timeout 区别是spring超时也不会立即停止,而是等待测试结束,计算总时间。包括重复的时间。
@Repeat
表示改测试将会重复执行N次
package com.superschool.test.demo;
import javax.annotation.Resource;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.Repeat;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionConfiguration;
import com.superschool.service.TestI;
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:/com/superschool/resource/spring/context/application/applicationContext.xml",
"classpath:/com/superschool/resource/spring/context/web/superschool-servlet.xml" })
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class TestA {
@Resource
private TestI test;
@BeforeTransaction
public void beforeTransaction() {
System.out.println("事物开始了");
}
@Repeat(10)
@DirtiesContext
@Test
@Rollback(false)
public void testMy() {
Assert.assertTrue(test.test());
}
}
另外还支持spring的其他所有注解。
@Autowired
• @Qualifier
• @Resource (javax.annotation) if JSR-250 is present
• @Inject (javax.inject) if JSR-330 is present
• @Named (javax.inject) if JSR-330 is present
• @Provider (javax.inject) if JSR-330 is present
• @PersistenceContext (javax.persistence) if JPA is present
• @PersistenceUnit (javax.persistence) if JPA is present
• @Required
• @Transactional
TestContextManager是测试的入口。
TestExecutionListener定义了监视时间的API
上下文的管理一般不会去理会,但是有时候需要访问的话
可以
package com.superschool.test.demo;
import javax.annotation.Resource;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.annotation.Repeat;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.GenericXmlContextLoader;
import org.springframework.test.context.transaction.BeforeTransaction;
import org.springframework.test.context.transaction.TransactionConfiguration;
import com.superschool.service.TestI;
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:/com/superschool/resource/spring/context/application/applicationContext.xml",
"classpath:/com/superschool/resource/spring/context/web/superschool-servlet.xml" }, loader = GenericXmlContextLoader.class)
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class TestA {
@Resource
private TestI test;
@Autowired
private ApplicationContext applicationContext;
@BeforeTransaction
public void beforeTransaction() {
System.out.println("事物开始了");
}
@Repeat(10)
@DirtiesContext
@Test
@Rollback(false)
public void testMy() {
Assert.assertTrue(test.test());
}
}
@ContextConfiguration(locations = {
"classpath:/com/superschool/resource/spring/context/application/applicationContext.xml",
"classpath:/com/superschool/resource/spring/context/web/superschool-servlet.xml" }, loader = GenericXmlContextLoader.class)
这里的loader=GenericXmlContextLoader.class可以不需要,因为它就是默认加载器。
默认情况下会加载当前包下面的MyTest-context.xml
如你的测试类是com.example.MyTest
那么会加载classpath:/com/example/MyTest-context.xml
另外如果要自己写classpath应该是classpath:/xx/xxxx/xxxx而不是classpath:xx/xxxx/xxxx
。因为如果写classpath:/xx/xxxx/xxxx它会在当前包下面查找xx.xxxx子包的xxxx文件
正常情况下ApplicationContext只加载一次,这个测试类之后的测试都重用一个applicationcontext。
inheritLocations属性 表示从父类加载。
默认是true
@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/base-context.xml" in the root of the classpath
@ContextConfiguration("/base-context.xml")
public class BaseTest {
// class body...
}
// ApplicationContext will be loaded from "/base-context.xml" and "/extended-context.xml"
// in the root of the classpath
@ContextConfiguration("/extended-context.xml")
public class ExtendedTest extends BaseTest {
// class body...
}
默认情况下会自动配置一个DependencyInjectionTestExecutionListener的TestExecutionListeners。它会自动注入属性。
如
@RunWith(SpringJUnit4ClassRunner.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration("daos.xml")
public final class HibernateTitleDaoTests {
// this instance will be dependency injected by type
@Autowired
private HibernateTitleDao titleDao;
public void testLoadTitle() throws Exception {
Title title = this.titleDao.loadTitle(new Long(10));
assertNotNull(title);
}
}
@RunWith(SpringJUnit4ClassRunner.class)
// specifies the Spring configuration to load for this test fixture
@ContextConfiguration("daos.xml")
public final class HibernateTitleDaoTests {
// this instance will be dependency injected by type
private HibernateTitleDao titleDao;
@Autowired
public void setTitleDao(HibernateTitleDao titleDao) {
this.titleDao = titleDao;
}
public void testLoadTitle() throws Exception {
Title title = this.titleDao.loadTitle(new Long(10));
assertNotNull(title);
}
}
这种方式完全符合spring的注入规则。包括Resource注解。Qualifier注解
默认情况下会自动配置一个TransactionalTestExecutionListener。但是你必须设置的PlatformTransactionManager bean
如
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
另外还要加入
@Transactional
测试支持类
org.springframework.test.context.junit4包
运行器
@RunWith(SpringJUnit4ClassRunner.class)
会自动加载配置