今天有点空了,把单元测试的那点事整理了一下。个人觉得Spring应用和Mockito结合做单元测试简单实用,分享出来供参考。
这里不啰嗦单元测试的重要性...。很多应用是基于Spring,而Mockito简单易用易上手,所以就把Spring和Mockito组合做单元测试,Mocked对象也交给Spring统一管理。好处至少有:使单元测试类的环境和应用实际的环境保持一致性。开发人员就不用另外增加额外的配置,也可以少一些代码。单元测试类通过了,相应的应用类也就ok(Spring的相关配置也ok)。
1,为了把Mock对象也纳入Spring。需继承DependencyInjectionTestExecutionListener并增加Mock对象和注入依赖对象为Mock对象。
代码:
public class MockitoDependencyInjectionTestExecutionListener extends DependencyInjectionTestExecutionListener {
private static final Map<String, MockObject> mockObject = new HashMap<String, MockObject>();
private static final List<Field> injectFields = new ArrayList<Field>();
@Override
protected void injectDependencies(final TestContext testContext) throws Exception {
super.injectDependencies(testContext);
init(testContext);
}
protected void injectMock(final TestContext testContext) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
AutowireCapableBeanFactory beanFactory = testContext.getApplicationContext().getAutowireCapableBeanFactory();
for (Field field : injectFields) {
Object o = beanFactory.getBean(field.getName(), field.getType());
if (null != o) {
Method[] methods = o.getClass().getDeclaredMethods();
for (Method method : methods) {
if (method.getName().startsWith("set")) {
for (Iterator it = mockObject.keySet().iterator(); it.hasNext();) {
String key = (String) it.next();
if (method.getName().equalsIgnoreCase("set" + key)) {
method.invoke(o, mockObject.get(key).getObj());
break;
}
}
}
}
}
}
}
private void init(final TestContext testContext) throws Exception {
Object bean = testContext.getTestInstance();
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
Annotation[] annotations = field.getAnnotations();
for (Annotation antt : annotations) {
if (antt instanceof org.mockito.Mock) {
// 注入mock实例
MockObject obj = new MockObject();
obj.setType(field.getType());
obj.setObj(mock(field.getType()));
field.setAccessible(true);
field.set(bean, obj.getObj());
mockObject.put(field.getName(), obj);
} else if (antt instanceof Autowired) {
// 只对autowire重新注入
injectFields.add(field);
}
}
}
for (Field field : injectFields) {
field.setAccessible(true);
Object object = field.get(bean);
if (object instanceof Proxy) {
// 如果是代理的话,找到真正的对象
Class targetClass = AopUtils.getTargetClass(object);
if (targetClass == null) {
// 可能是远程实现
return;
}
Field[] targetFields = targetClass.getDeclaredFields();
for (int i = 0; i < targetFields.length; i++) {
// 针对每个需要重新注入的字段
for (Map.Entry<String, MockObject> entry : mockObject.entrySet()) {
// 针对每个mock的字段
if (targetFields[i].getName().equals(entry.getKey())) {
targetFields[i].setAccessible(true);
targetFields[i].set(getTargetObject(object, entry.getValue().getType()),
entry.getValue().getObj());
}
}
}
} else {
injectMock(testContext);
}
}
}
protected <T> T getTargetObject(Object proxy, Class<T> targetClass) throws Exception {
if (AopUtils.isJdkDynamicProxy(proxy)) {
return (T) ((Advised) proxy).getTargetSource().getTarget();
} else {
return (T) proxy; // expected to be cglib proxy then, which is simply a specialized class
}
}
public static class MockObject {
private Object obj;
private Class<?> type;
public MockObject(){
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public Class<?> getType() {
return type;
}
public void setType(Class<?> type) {
this.type = type;
}
}
public static Map<String, MockObject> getMockobject() {
return mockObject;
}
public static List<Field> getInjectfields() {
return injectFields;
}
}
2,单元测试继承AbstractJUnit4SpringContextTests类。这里用一个抽象类把必须的注解上。
代码:
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({ MockitoDependencyInjectionTestExecutionListener.class })
public abstract class BaseTestCase extends AbstractJUnit4SpringContextTests {
}
3,测试用例 demo。注意在MockitoDependencyInjectionTestExecutionListener中已经mock对象了,不要再用MockitoAnnotations.initMocks(this)。
代码:
@ContextConfiguration(locations = { "/applicationContext.xml" })
public class DemoServiceTest extends BaseTestCase {
@Autowired
private DemoService demoService;
@Mock
private DemoDao demoDao;
@Test
public void testGetResults() {
List<Model> list = new ArrayList<Model>();
Model model = new Model("id", "name");
list.add(model);
// 先设置预期
when(demoDao.getModel("id")).thenReturn(model);
// when(demoDao.getResults()).thenAnswer(new Answer<List<Model>>() {
//
// @Override
// public List<Model> answer(InvocationOnMock invocation) throws Throwable {
// List<Model> list = new ArrayList<Model>();
// Model model = new Model("id", "name");
// list.add(model);
// return list;
// }
//
// });
Model m = demoService.getModel("id");
assertSame(m, model);
// List<Model> result = demoService.getResults();
// assertTrue(result.size() == 1);
}
}
分享到:
相关推荐
在SpringBoot项目中,JUnit与Mockito等工具结合,可以有效地对服务层、DAO层进行单元测试。 6. **tk-demo-master**: 这个文件名可能是一个Git仓库的主分支名称,暗示这个压缩包包含了一个基于SpringBoot、TK...
Spring、Struts2和Hibernate是Java开发中三大主流的开源框架,它们的组合通常被称为SSH(Spring、Struts2、Hibernate)集成框架。这个组合在企业级应用开发中被广泛使用,提供了强大的功能和灵活性,使得开发人员...
5. **集成测试**:Spring Test模块提供了对Spring应用进行单元测试和集成测试的支持,包括Mockito、JUnit等测试工具的集成。 6. **WebSocket支持**:Spring Framework 4.x引入了WebSocket API,使得开发实时双向...
- **整合测试**:如何使用JUnit和Mockito等工具进行集成测试,验证三大框架的协同工作。 此外,可能还会涉及其他实用功能,如异常处理、视图解析、国际化支持等,以及在实际项目中的最佳实践和常见问题解决方案。 ...
7. 持续集成与测试:学习如何使用JUnit进行单元测试,Mockito进行模拟对象测试,以及如何配置Maven或Gradle进行项目的构建和依赖管理。 通过深入学习这些知识点,并结合提供的压缩包资料,开发者可以更好地掌握SSH...
对于测试,Spring Boot也提供了spring-boot-starter-test启动器,该启动器集成了JUnit、Hamcrest和Mockito等库,便于开发者编写测试用例。 Spring Boot的起步依赖遵循一个命名规则,即spring-boot-starter-加上应用...
对于测试,JUnit和Mockito可以帮助我们编写单元测试,保证代码质量。 总的来说,SSM+maven的组合为开发者提供了一个高效、可维护的Java Web应用开发平台。通过合理的配置和模块划分,可以快速构建出功能完善的后台...
JUnit和Mockito可以用来编写单元测试,而Spring Boot Test则支持集成测试,确保各个模块协同工作。 9. **版本控制**:使用Git进行版本控制,可以帮助团队协作和代码管理,同时记录每次修改的历史,方便回溯和解决...
9. **单元测试**:使用JUnit或Mockito进行单元测试,确保代码质量及功能的正确性。 10. **部署与运行环境**:系统可能运行在Tomcat或Jetty等应用服务器上,依赖Maven或Gradle等构建工具进行项目构建和依赖管理。 ...
6. **测试框架集成**:集成了JUnit和Mockito,方便进行单元测试和集成测试。 三、核心组件解析 1. **Spring MVC**:SpringSide中的Web层基于Spring MVC,通过Controller、Service、DAO三层架构实现业务逻辑。 2. **...
SSM框架是Java web开发中常用的三大框架Spring、Spring MVC和MyBatis的组合,它在电子商务平台的设计与实现中起到了关键作用。本项目通过利用SSM框架,构建了一个功能完善的电子商务平台,涵盖了用户管理、商品展示...
-单元测试框架如JUnit和Mockito:用于编写和执行测试用例,确保代码质量。 在分析源码时,可以从以下几个方面入手: 1. **项目结构**:理解项目的目录结构,包括src/main/java和src/main/resources等,了解各个包的...
利用JUnit、Mockito等工具对SSM中的各个组件进行单元测试,同时使用Spring Boot的TestRestTemplate进行集成测试,确保代码质量。 9. **文档编写**: 提供详细的使用说明文档,介绍项目结构、部署步骤、功能实现及...
此外,项目中的测试有效,意味着开发过程中可能采用了单元测试和集成测试,如JUnit和Mockito等工具,以确保各个模块的正确性。测试是软件质量保证的重要环节,能够及时发现和修复问题,提升软件稳定性。 总结,...
9. **测试与调试**:使用JUnit进行单元测试,Mockito模拟对象以隔离测试,而集成测试则可能需要如Spring Boot Test的支持。Eclipse或IntelliJ IDEA等IDE中的调试工具可以帮助找出并修复问题。 10. **持续集成与部署...
9. **测试**:单元测试、集成测试的概念,JUnit或Mockito等测试框架的使用。 10. **版本控制**:如Git的使用,团队协作和代码管理。 11. **Spring Boot**:虽然题目中没有直接提到,但了解Spring Boot能简化Spring...
8. **测试**:SpringBoot提供丰富的测试工具,如JUnit、Mockito等,便于单元测试和集成测试,确保系统功能的正确性。 总之,这个基于SpringBoot的在线考试与学习交流平台利用了Java生态系统中的强大工具,实现了从...
6. **单元测试和集成测试**:使用JUnit和Mockito进行代码测试。 7. **前端框架**:如Vue.js、React或Angular,用于构建用户界面。 8. **微信开发者工具**:用于调试和部署微信小程序。 总之,这个项目综合运用了...
9. **单元测试和集成测试**:为了确保代码质量和系统稳定性,开发者可能会使用JUnit和Mockito等工具进行单元测试,以及Spring Boot的TestRestTemplate进行集成测试。 10. **持续集成/持续部署(CI/CD)**:项目可能...
6. **测试**: Spring Boot包含了JUnit和Mockito等测试库,使得单元测试和集成测试变得简单。Kotlin的协程支持还可以让异步测试变得更易管理。 在这个项目中,我们可能会看到`.kt`文件,它们是Kotlin源代码文件,...