unit测试

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)
会自动加载配置
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值