Mock&Spring集成#

常规Mock单元测试##

请参考上一篇文档Mock

mock框架的功能性对比##

http://jmockit.github.io/MockingToolkitComparisonMatrix.html

从模拟支持特性上做了详细的对比,比如是否支持模拟static、构造函数等等。

集成测试##

大部分Web应用项目基于Spring平台构建,集成测试主要关注点是Junit+Spring+Mock集成!

从Spring项目2.x开始就有基于Junit的测试辅助包(Spring-test)!

重点关注引入Mock框架后Spring与其集成!

温馨提示Jmockit作为本文代码示例的模拟框架,其它模拟选型框架的测试结果直接作为结论。

关注点##

Mock测试框架是否能够和Spring完美集成?

  • 版本&升级(mock框架版本和Spring版本是否完全兼容,无包冲突,是否可升级,比如Spring从2.x->3.x->4.x)
  • 内容&特性(mock框架提供的各种模拟策略特性能否和Spring-test提供的各种测试支持类兼容)

基于Spring的测试点##

虚拟机运行环境版本: 1.7.0_60

1)基础包版本:

  • Spring:2.5.6/3.x.x/4.x.x, Junit:4.x

2)Mock选型:

  • Mockito:1.9.5, PowerMock-mockito-*: 1.5.5
  • Jmock:2.6.0
  • Jmockit:1.14

3)模拟测试用例

  • 模拟Spring单例bean方法
  • 模拟静态方法调用

备注:实际测试是分开多个测试Demo,spring+mockito

示例代码##

UserService,StaticUserService,UserAction类请参考上一篇文档Mock

静态公共方法模拟###

package jmockit;

import mockit.NonStrictExpectations;
import mockit.Verifications; import org.junit.Test;
import org.wit.service.StaticUserService;
import org.wit.service.UserAction; public class MockForPublicStaticDemo { @Test
public void demo() {
new NonStrictExpectations(StaticUserService.class) {
{
StaticUserService.sayHello(anyString);
result = "mock";
}
}; // assertEquals("mock", StaticUserService.sayHello("real"));
UserAction userAction = new UserAction();
userAction.executeForPublicStatic1("real"); new Verifications() {
{
StaticUserService.sayHello(anyString);
times = 1;
}
};
}
}

Spring Singleton Bean方法模拟###

package jmockit;

import mockit.NonStrictExpectations;
import mockit.Verifications; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.wit.service.StaticUserService;
import org.wit.service.UserAction;
import org.wit.service.UserService; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class MockForSpringJunitDemo { @Autowired
private UserAction userAction; @Autowired
private UserService userService; @Test
public void demo() throws Exception {
new NonStrictExpectations(StaticUserService.class) {
{
StaticUserService.sayHello(anyString);
result = "mock";
}
}; userAction.executeForPublicStatic1("real"); new Verifications() {
{
StaticUserService.sayHello(anyString);
times = 1;
}
}; } /**
*
* <pre>
* 模拟bean的方法.
* UserService sayHello模拟调用, sayHi为真实调用.
* </pre>
*
* @throws Exception
*/
@Test
public void beanDemo() throws Exception{
new NonStrictExpectations(userService) {
{
userService.sayHello(anyString);
result = "mock";
}
}; userAction.executeForPublic("hi"); new Verifications() {
{
userService.sayHello(anyString);
times = 1;
}
}; }
}

静态私有方法模拟###

package jmockit;

import static mockit.Deencapsulation.invoke;
import mockit.Expectations;
import mockit.Verifications; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.wit.service.StaticUserService;
import org.wit.service.UserAction; @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class MockForSpringJunitPrivateStaticDemo { @Autowired
private UserAction userAction; @Test
public void demo() throws Exception { new Expectations(StaticUserService.class) {
{
invoke(StaticUserService.class, "secreteSayHi", anyString);
invoke(StaticUserService.class, "secreteSayHello", anyString);
result = "mock";
} }; userAction.executeForPrivateStatic("real"); new Verifications() {
{
invoke(StaticUserService.class, "secreteSayHi", anyString);
times = 1;
invoke(StaticUserService.class, "secreteSayHello", anyString);
times = 1;
}
};
} }

结论##

方案:Mockito:1.9.5, PowerMock-mockito-*: 1.5.5

  • Spring-test 3.x以上版本启用了新测试基类,并提供新的测试运行器(SpringJunit4ClassRunner.class), 它会和PowerMock提供的测试运行器(PowerMockRunner.class)产生冲突,如果选择PowerMockRunner会导致找不到Spring配置文件的错误发生;
  • Spring-test 2.5.6的测试基类AbstractDependencyInjectionSpringContextTests和PowerMock兼容,但此类在Spring3.x之后的版本中过时。
  • 采用官方提供的PowerMockRule会产生虚拟机崩溃的错误详细日志见下文
2015-11-27 15:58:48,015 INFO  context.TestContextManager - Could not instantiate TestExecutionListener class [org.springframework.test.context.web.ServletTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their dependencies) available.
2015-11-27 15:58:48,019 INFO context.TestContextManager - Could not instantiate TestExecutionListener class [org.springframework.test.context.transaction.TransactionalTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their dependencies) available.
2015-11-27 15:58:48,112 INFO xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [applicationContext.xml]
2015-11-27 15:58:48,191 INFO support.GenericApplicationContext - Refreshing org.springframework.context.support.GenericApplicationContext@361fc5a2: startup date [Fri Nov 27 15:58:48 GMT+08:00 2015]; root of context hierarchy
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000000291e2ba, pid=15700, tid=14928
#
# JRE version: Java(TM) SE Runtime Environment (7.0_60-b13) (build 1.7.0_60-ea-b13)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (24.60-b09 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# j java.lang.reflect.ReflectAccess.copyField(Ljava/lang/reflect/Field;)Ljava/lang/reflect/Field;+1
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# D:\workspace\workspace-demos\mockito\hs_err_pid15700.log
Compiled method (c2) 861 16 java.lang.Object::<init> (1 bytes)
total in heap [0x0000000002969310,0x0000000002969540] = 560
relocation [0x0000000002969430,0x0000000002969440] = 16
main code [0x0000000002969440,0x00000000029694c0] = 128
stub code [0x00000000029694c0,0x00000000029694d8] = 24
oops [0x00000000029694d8,0x00000000029694e0] = 8
scopes data [0x00000000029694e0,0x00000000029694f0] = 16
scopes pcs [0x00000000029694f0,0x0000000002969520] = 48
dependencies [0x0000000002969520,0x0000000002969528] = 8
handler table [0x0000000002969528,0x0000000002969540] = 24
#
# If you would like to submit a bug report, please visit:
# http://bugreport.sun.com/bugreport/crash.jsp
#

方案: Jmock:2.6.0,Jmockit:1.14

  • Jmock&Jmockit在测试运行器上选择Spring的测试运行器,和Spring各个版本兼容良好。
  • 模拟Spring 单例Bean的方法和静态方法都能正常模拟,请关注静态私有方法和公共方法的差异

QA##

Mock&Spring集成的更多相关文章

  1. 从零开始学 Java - Spring 集成 Memcached 缓存配置(二)

    Memcached 客户端选择 上一篇文章 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)中我们讲到这篇要谈客户端的选择,在 Java 中一般常用的有三个: Memc ...

  2. 从零开始学 Java - Spring 集成 ActiveMQ 配置(一)

    你家小区下面有没有快递柜 近两年来,我们收取快递的方式好像变了,变得我们其实并不需要见到快递小哥也能拿到自己的快递了.对,我说的就是类似快递柜.菜鸟驿站这类的代收点的出现,把我们原来快递小哥必须拿着快 ...

  3. 【转】Dubbo使用例子并且和Spring集成使用

    一.编写客户端和服务器端共用接口类1.登录接口类public interface LoginService {    public User login(String name, String psw ...

  4. 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)

    硬盘和内存的作用是什么 硬盘的作用毫无疑问我们大家都清楚,不就是用来存储数据文件的么?如照片.视频.各种文档或等等,肯定也有你喜欢的某位岛国老师的动作片,这个时候无论我们电脑是否关机重启它们永远在那里 ...

  5. axis2+spring集成

    转载自:http://www.cnblogs.com/linjiqin/archive/2011/07/05/2098316.html 1.新建一个web project项目,最终工程目录如下: 注意 ...

  6. rabbitMQ第五篇:Spring集成RabbitMQ

    前面几篇讲解了如何使用rabbitMq,这一篇主要讲解spring集成rabbitmq. 首先引入配置文件org.springframework.amqp,如下 <dependency> ...

  7. 从零开始学 Java - Spring 集成 ActiveMQ 配置(二)

    从上一篇开始说起 上一篇从零开始学 Java - Spring 集成 ActiveMQ 配置(一)文章中讲了我关于消息队列的思考过程,现在这一篇会讲到 ActivMQ 与 Spring 框架的整合配置 ...

  8. spring集成常用技术的配置

    使用spring集成其他技术,最基本的配置都是模板化的,比如配置视图模板引擎.数据库连接池.orm框架.缓存服务.邮件服务.rpc调用等,以spring的xml配置为例,我将这些配置过程整理出来,并不 ...

  9. Activiti工作流学习(三)Activiti工作流与spring集成

    一.前言 前面Activiti工作流的学习,说明了Activiti的基本应用,在我们开发中可以根据实际的业务参考Activiti的API去更好的理解以及巩固.我们实际的开发中我们基本上都使用sprin ...

随机推荐

  1. RabbitMQ消息队列(九)RPC开始应用吧

    一 简单应用 RPC——远程过程调用,通过网络调用运行在另一台计算机上的程序的函数\方法,是构建分布式程序的一种方式.RabbitMQ是一个消息队列系统,可以在程序之间收发消息.利用RabbitMQ可 ...

  2. 简单粗暴地理解js原型链–js面向对象编程

    简单粗暴地理解js原型链–js面向对象编程 作者:茄果 链接:http://www.cnblogs.com/qieguo/archive/2016/05/03/5451626.html 原型链理解起来 ...

  3. AndroidStudio构建常见错误解答解决思路

    一.Error:Configuration with name 'default' not found.解决思路 出现这问题的原因是你依赖的工程没有make project,意思是你导入项目的工程没有 ...

  4. Linux环境安装xmapp(PHP-Mysql集成环境)

    xmapp是很多初学者使用的PHP环境集成包,用yum在linux安装的php和mysql版本现在都很低,xmapp可以解决这个问题,下面我们直接进入正题,安装一个php集成环境. 我使用的是vm虚拟 ...

  5. CentOS7 开通特定防火墙端口

    >>> 开启端口 firewall-cmd --zone=public --add-port=/tcp --permanent  命令含义: --zone #作用域 --add-po ...

  6. 剑指offer--49.矩阵中的路径

    时间限制:1秒 空间限制:32768K 热度指数:156998 题目描述 请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径.路径可以从矩阵中的任意一个格子开始,每一步可以在矩 ...

  7. Python中的单例设计模式

    1)设计模式: 是前人工作的总结和提炼.通常,被人们广泛流传的设计模式.     某一问题的特定解决方案,使用设计模式是为了可重用代码,是代码更容易被人理解, 增加代码的可用性. 2)单例设计模式: ...

  8. 使用treemap 遍历map参数

    遍历格式 XXX=123&XXX=456.....参数为map treemap是一个有序的key-value集合,它是通过红黑树实现的 TreeMap<String, String> ...

  9. three.js入门系列之粒子系统

    其实代码很简单,也很容易懂(我用的是r99版本的three.js,目前网上大多数demo是60或者80的版本,其中的一些api已经废弃,如下是r99版本支持的写法): 注:渲染器是WebGl渲染器 如 ...

  10. vueRouter中scrollBehavior实现滚动固定位置

    使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样. vue-router 能做到,而且更好,它让你可以自定义路由切换时页面如何滚动. 注意: 这个功能只 ...