本文主要是提供了一种解决方案,用于解决spring管理的测试用例在mock过程中,如何有效管理mock宿主和mock实体,并优化mock方法
一、基础类
1、Sping配置基础
@ContextConfiguration(locations = { "classpath:spring.xml" })
public abstract class BaseServiceTest extends
AbstractTransactionalJUnit4SpringContextTests {
/**
* 日志器
*/
protected Logger logger = LoggerFactory.getLogger(getClass());
/**
* 确认已有异常被抛出
*/
protected void checkExceptionRaise() {
Assert.assertTrue("can't reach here, a exception should be raised",
false);
}
}
2、通用测试基类
public abstract class BaseTest<T> extends BaseServiceTest {
private final Set<MockField> mockFields = new HashSet<MockField>();
/**
* 既可 mock 接口也可以 mock 类
*/
protected final Mockery context = new JUnit4Mockery() {
{
setImposteriser(ClassImposteriser.INSTANCE);
}
};
/**
*
*/
@After
public void restoreField() {
context.assertIsSatisfied();
for (final MockField mockField : mockFields) {
ReflectionTestUtils.setField(mockField.getToMock(),
mockField.getFieldName(), mockField.getNativeValue());
}
}
/**
* 提取实体类型信息
*
* @return 实体类型信息
*/
private Class<T> extractGenericParameterInfo() {
for (Class<?> current = getClass(); (current != BaseTest.class)
|| (current != Object.class); current = current.getSuperclass()) {
final Type genericSuperType = current.getGenericSuperclass();
if (!(genericSuperType instanceof ParameterizedType)) {
continue;
}
final ParameterizedType genericSuperClass = (ParameterizedType) genericSuperType;
final Type[] actualTypes = genericSuperClass
.getActualTypeArguments();
if (actualTypes.length == 0) {
continue;
}
final Type firstType = actualTypes[0];
if (!(firstType instanceof Class)) {
continue;
}
@SuppressWarnings("unchecked")
final Class<T> firstClass = (Class<T>) firstType;
return firstClass;
}
throw new IllegalStateException("无法获取有效的模板参数信息");
}
/**
* @return
*/
private Object getMockHost() {
Object toMock = getToMock();
if (toMock != null) {
return toMock;
}
final Field[] fields = this.getClass().getDeclaredFields();
for (final Field field : fields) {
final Class<T> genericParameterInfo = extractGenericParameterInfo();
if (genericParameterInfo.isAssignableFrom(field.getType())) {
Assert.assertNull("重复的mock宿主", toMock);
toMock = ReflectionTestUtils.getField(this, field.getName());
}
}
Assert.assertNotNull("mock宿主不能为空", toMock);
return toMock;
}
/**
* @return mock宿主
*/
protected Object getToMock() {
return null;
}
/**
* 为本测试用例指定的mock宿主,通过<code>getToMock()</code>指定,设置指定类型的mock实体
*
* @param <E>
* mock实体类型
* @param typeToMock
* 用来mock的实体类型
* @return mock实体
*/
protected <E> E mock(final Class<E> typeToMock) {
final E mockObject = context.mock(typeToMock);
final Object toMock = getMockHost();
String fieldName = null;
final Field[] fields = toMock.getClass().getDeclaredFields();
for (final Field field : fields) {
if (typeToMock.isAssignableFrom(field.getType())) {
Assert.assertNull("重复的mock实体", fieldName);
fieldName = field.getName();
}
}
Assert.assertNotNull("无法定位mock实体", fieldName);
mock(toMock, fieldName, mockObject);
return mockObject;
}
/**
* mock对象
*
* @param <E>
* mock对象类型
*
* @param toMock
* mock宿主
* @param fieldName
* 属性名称
* @param typeToMock
* 用来mock的对象类型
* @return mock对象
*/
protected <E> E mock(final Object toMock, final String fieldName,
final Class<E> typeToMock) {
final E mockObject = context.mock(typeToMock);
mock(toMock, fieldName, mockObject);
return mockObject;
}
/**
* @param toMock
* 用来插入mock对象的大对象
* @param fieldName
* 属性名称
* @param mockObject
* mock对象
*/
protected void mock(final Object toMock, final String fieldName,
final Object mockObject) {
final MockField mockField = new MockField();
mockField.setFieldName(fieldName);
mockField.setNativeValue(ReflectionTestUtils
.getField(toMock, fieldName));
mockField.setToMock(toMock);
Assert.assertTrue("不允许重复mock", !mockFields.contains(mockField));
mockFields.add(mockField);
ReflectionTestUtils.setField(toMock, fieldName, mockObject);
}
/**
* 为本测试用例指定的mock宿主,通过<code>getToMock()</code>指定,设置指定类型的mock实体
*
* @param fieldName
* 指定的属性名称
*
* @param <E>
* mock实体类型
* @param typeToMock
* 用来mock的实体类型
* @return mock实体
*/
protected <E> E mock(final String fieldName, final Class<E> typeToMock) {
final E mockObject = context.mock(typeToMock);
mock(getToMock(), fieldName, mockObject);
return mockObject;
}
}
3、派生自该基类的测试类实例
public class XXXXTest extends BaseTest<XXXXX > {
@Autowired
private XXXXX xxxxx;
@Test
public void testTTTTTTT() {
final YYYYY mockYYYYY = mock(YYYYYY.class);
context.checking(new Expectations() {
{
oneOf(mockYYYYY).doSomething()
will(returnValue(true))
}
});
Assert.assertTrue(phaseManageBizImpl.TTTTTTT());
}
}
二、技术难点
1、mock对象的还原,能够使spring的对象不被单个测试用例破坏
如果不剥离注入到mock宿主中的mock实体,下次再次使用该mock宿主时,由于spring不会对bean再次进行初始化,因此第二次使用的mock宿主行为是不可控的。
2、使用反射简化mock接口
三、优势
1、使用@after和@before完成,不需要增加单个测试用例的工作量
2、获取mock实体时方法简单
final YYYYY mockYYYYY = mock(YYYYYY.class);
可以直接mock掉XXXXX中的YYYYY类型变量,不需要指定宿主和实体名字即可完成mock对象注入和剥离
3、能够通过指定属性名进行扩展
mock方法有多个overwrite,允许通过指定field那么来注入mock实体
分享到:
相关推荐
Spring框架是Java开发中的核心组件,它为应用程序提供了一个全面的基础设施,包括依赖注入(DI)、面向切面编程(AOP)以及数据访问等。Spring5是该框架的一个重要版本,引入了许多新特性以增强其功能和性能。下面将...
如果项目是一个完整的 Web 应用,并且将全程使用 Spring 框架,推荐使用单个完整的 `spring.jar` 文件,因为它包含了除 `spring-mock.jar` 外的所有 Jar 包内容。 如果只需要使用 Spring 的 IoC/DI 容器特性,则只...
在描述中提到的PowerDesigner源文件可能是用来设计和分析Spring框架中各jar包的依赖关系的,这是一种常见的建模工具,可以帮助开发者更好地理解复杂系统的结构。图片"Spring框架jar依赖关系.jpg"和".png"应该是展示...
Spring 框架是Java开发中的一个核心框架,它为构建可维护、模块化和松耦合的应用程序提供了全面的支持。3.2.0.RELEASE 版本是 Spring 框架的一个稳定版本,...理解并掌握这些依赖对于有效地利用Spring框架至关重要。
Spring框架是Java开发中不可或缺的一部分,它以其模块化、易扩展和高度可配置性而闻名。Spring 4.2.3版本是该框架的一个稳定版本,提供了许多改进和新特性。这个官方包针对的是工程应用,专注于核心的jar文件,去除...
现在我们详细探讨一下Spring框架及其相关的jar包。 首先,"spring_4.3.3"这个压缩包可能包含了Spring框架4.3.3版本的所有必要组件。在4.x系列版本中,Spring进行了大量的优化和增强,提供了更好的性能和更多的功能...
该文档是Spring框架开发者的宝贵资源,帮助开发者深入理解并有效利用Spring框架解决实际问题。无论对于初学者还是有经验的开发者,通过阅读此文档,都可以加深对Spring编程模型、架构细节和应用集成方面的理解。
在“spring-framework-4.3.8.RELEASE”这个压缩包中,包含的是Spring框架的4.3.8版本。这是一个稳定版本,发布于2017年,它提供了一系列增强和修复,以提高性能和稳定性。下面将详细介绍Spring框架的关键组成部分和...
Spring框架是Java开发中最常用的轻量级框架之一,它的2.0.8版本是一个历史悠久但仍然具有重要学习价值的里程碑。这个源码包包含了Spring框架的核心组件和相关模块,为开发者提供了深入理解Spring工作原理的机会。 ...
Spring 2.0是Spring框架的一个重要版本,它在2006年发布,标志着Spring框架的显著进步和发展。这个版本引入了许多新特性,优化了已有功能,并为开发者提供了更强大的工具来构建企业级Java应用。以下是Spring 2.0中的...
这个描述意味着用户无需逐一下载和管理Spring框架的各个模块,只需将提供的压缩包导入到项目的库(lib)目录下,即可方便地在项目中使用Spring的所有功能。 Spring是一个广泛使用的Java企业级应用开发框架,其核心...
Spring 框架是Java开发中的一个核心框架,它提供了全面的应用程序开发模型,支持从简单的单个bean...同时,考虑到Spring框架不断演进,新版本通常会引入更多新功能和改进,所以升级到更高版本也是一个值得考虑的选择。
Spring 是Java企业级应用的核心框架,提供了一个全面的基础设施,用于构建高质量的、模块化的、可测试的应用程序。Struts 是一个基于MVC(Model-View-Controller)设计模式的Java Web框架,用于简化创建用户交互界面...
Spring框架是Java开发中不可或缺的一部分,它以其模块化、易扩展和强大的依赖注入特性而闻名。Spring 5.0.6版本是该框架的一个稳定版本,提供了许多改进和新功能。这个版本的jar包是Spring核心组件的基础,适用于...
在Java开发领域,Spring框架以其强大的功能和灵活性,成为了企业级应用的首选。其中,`spring-test`模块是Spring框架的一部分,专为集成测试提供了一整套工具和支持。本文将详细探讨`spring-test-3.2.0.RELEASE.jar`...
这是一个包含Spring框架完整发布模块的单一jar包,但不包括mock.jar、aspects.jar、spring-portlet.jar和spring-hibernate2.jar。对于那些需要完整功能的项目,可以考虑使用此jar包。 2. **spring-core.jar**: ...
Spring框架是Java开发中广泛应用的轻量级框架,它的出现极大地简化了企业级应用的开发。Spring1.x和Spring2.x版本之间的差异主要体现在功能增强、性能优化以及对其他技术的支持上。以下将详细阐述这两个版本的主要...
Spring 2.5是Spring框架的一个重要版本,它在2008年发布,引入了许多增强的功能和改进,为开发者提供了更加完善的Java企业级应用开发环境。在这个版本中,Spring框架进一步提升了其灵活性、可扩展性和易用性,使得...
### Spring 4.3 开发手册知识点概览 #### 一、Spring框架概述 - **Spring框架简介**:Spring框架是一种轻量级的Java开发...对于开发者来说,深入了解这些知识点有助于更好地掌握Spring框架的使用技巧,提高开发效率。
Spring框架是Java开发中不可或缺的一部分,它以其模块化、易用性和灵活性著称。Spring 3.1 是该框架的一个重要版本,引入了许多改进和新特性,为开发者提供了更强大的功能支持。在这个“最新 spring3.1 完整jar包”...