一、在eclipse下建立JMockit工程

1、下载最新版JMockit(jmockit-1.4.zip);

2、解压后的文件夹包含有:library jars, source files, samples, API javadocs, and additional documentation;

3、将jmockit.jar添加到项目classpath中;

特别的:

1)确保classpath中Jar包的顺序:jmockit的jar包必须在junit之前(通过Order and Export" 标签上下移动);

2)eclipse项目所用JRE来自于JDK,而不是“简洁”版的JRE,因为后者缺少本地类库“attach”。

二、行为和状态的测试

基于行为(Behavior-based)的mock是站在目标测试代码外面的角度的,通常主要模拟行为,而基于状态

(State-based)的是站在目标测试代码内部的。我们可以对传入的参数进行检查、匹配,才返回某些结果。

Mockup用于State-based测试。

二、声明和使用mock类型

1、字段,期望块的字段与期望块内的局部属性字段使用@Mocked来声明Mock类型。

2、参数,方法的参数声明来引入一个Mock类型。

第一种情况,属性字段是属于测试类或者一个mockit.Expectations子类(一个expectation期望块的内部的局部

属性字段)。

第二种情况,参数必须是属于某个测试方法(@Test标签下的方法)。

在所有的情况,一个mock属性字段或者参数声明,都可以通过使用@Mocked声明。对于方法mock的参数或者

在expectations期望块中定义的mock属性字段来说,该注解是可选的,而对于定义在测试类(XXXTest类)中的

属性字段,@Mocked标签是必须,这是为了防止和该测试类的其它不需要mock的字段属性产生冲突。

package main;

import static org.junit.Assert.*;

import java.io.Serializable;

import org.junit.Test;

import mockit.Expectations;

import mockit.Mocked;

import mockit.NonStrictExpectations;

import mockit.Verifications;

/*

* 一个用户接口(外部依赖)

*/

interface Dependency {

String doSomething(boolean b);

}

// 声明变量类型MultiMock(它实现两个接口,作用域是整个测试类)

public class MultiMocksTest<MultiMock extends Dependency & Runnable> {

@Mocked

MultiMock multiMock;

@Test

public void mockFieldWithTwoInterfaces() {

new NonStrictExpectations() {

{

multiMock.doSomething(false);

result = "test";

}

};

multiMock.run();

assertEquals("test", multiMock.doSomething(false));

// 验证run()方法执行一次

new Verifications() {

{

multiMock.run();

}

};

}

@Test

// 声明变量类型M,它实现两个接口,作用域为该测试方法

// final M mock 前的@Mocked注解是可选的

public <M extends Dependency & Serializable> void mockParameterWithTwoInterfaces(

@Mocked final M mock) {

new Expectations() {

{

mock.doSomething(true);

result = "";

}

};

assertEquals("", multiMock.doSomething(true));

}

}
 

3、对于一个返回值不为void类型的方法,Expectations中如何模拟方法返回值:

1)其返回值可以通过Expectations的result属性域来记录

2)Expectations的returns(Object)方法来记录

例如,方法返回一个Throwable异常类,只需将一个类型实验赋给result(注意,异常类只能通过result方式

赋值)。

package main;

import mockit.Expectations;

import org.junit.Test;

public class UnitUnderTest {

// 1、构造方法

private OutWork work = new OutWork();

public void doSomthing() {

// 2、intReturningMethod()方法

int n = work.intReturningMethod();

for (int i = 0; i < n; i++) {

String s;

try {

// 3、stringReturningMethod()方法

s = work.stringReturningMethod();

} catch (Exception e) {

// 处理异常

e.printStackTrace();

}

}

// 其它逻辑...

}

@Test

public void test() {

new Expectations() {

OutWork work;

{

// 1、构造方法模拟

new OutWork();

// 2、intReturningMethod()方法模拟

work.intReturningMethod();

result = 3;

// 3、stringReturningMethod()方法模拟

work.stringReturningMethod();

// 方法分别返回三个值,两个字符串,一个异常

returns("str1", "str2");

result = new Exception("testException");

}

};

new UnitUnderTest().doSomthing();

}

}

class OutWork {

public int intReturningMethod() {

return 0;

}

public String stringReturningMethod() {

return "";

}

}
 

三、从严格到非严格

1、@Mocked+Expections块:会进行隐式校验(执行顺序和次数)

2、@Mocked+NonStrictExpections块:NonStrictExpections块中的Incovation可以非严格执行(不执行或者

执行N次,除非显示地指定执行次数)。

package main;

/*

* 用于Mock的接口

*/

public interface WinportUrlService {

public boolean hasWinport(String id);

public String getMsg();

public Throwable getWinportUrlThrowException(String id);

}

package main;

import static org.junit.Assert.*;

import mockit.Expectations;

import mockit.Mocked;

import mockit.NonStrictExpectations;

import org.junit.Test;

public class IntroductionTest {

// @Mocked注解+Expectations/NonStrictExpectations块

@Mocked

private WinportUrlService winportUrlService = null;

@Test

public void testNoExceptions() {

final String memberId = "test";

// 未指定期望块,方法返回默认值

assertEquals(false, winportUrlService.hasWinport(memberId));

assertEquals(null, winportUrlService.getMsg());

assertEquals(null, winportUrlService.getWinportUrlThrowException(memberId));

}

@Test

public void testWithExpectations() {

final String memerId = "test";

// 步骤一:record

// 严格期望块

new Expectations() {

{

// 下面的Invocation必须严格执行

winportUrlService.hasWinport(memerId);

result = false;// 也可以是returns(false)

// 未指定执行次数

}

};

// 非严格期望块

new NonStrictExpectations() {

{

// 下面的Invocation非严格执行

winportUrlService.getMsg();

result = "test";// 也可以是returns("test")

// 未指定执行次数

}

};

// 步骤二:replay阶段

// hasWinport必须严格执行一次

assertEquals(false, winportUrlService.hasWinport(memerId));

// getMsg可以不执行或执行多次

assertEquals("test", winportUrlService.getMsg());

assertEquals("test", winportUrlService.getMsg());

// 下面的Invocation失败

// winportUrlService.getWinportUrlThrowException(memerId);

}

}

3、@NonStrict:可以在replay中调用或不调用。@NonStrict可以避免需要记录调用构造函数,或任何不感兴

趣的方法。

注意:@NonStrict它是针对类的属性非严格,类的属性适用于类中的所有测试方法。这个非严格的范围比

NonStrictExpections块的作用范围大很多,一旦使用了@NonStrict,Expections中的Incovation就变成了非严

格的invocation,因此其它测试方法还想在该属性的基础上使用Expections块是不可能的了。如果是这种情况

就需要这样使用(@Mocked+NonStrictExpectations块)。

package main;

import static org.junit.Assert.*;

import mockit.Expectations;

import mockit.NonStrict;

import org.junit.Test;

public class IntroductionTest2 {

// @NonStrict注解

@NonStrict

private WinportUrlService winportUrlService = null;

@Test

public void testWithExpectations() {

final String memberId = "test";

// 步骤一:record

// 用了@NonStrict,Expectation中的invocation就变成了非严格的invocation

new Expectations() {

{

// 下面的Invocation非严格执行

winportUrlService.hasWinport(memberId);

result = false;// 也可以是returns(false)

// 未指定执行次数

}

};

// 步骤二:replay阶段

// hasWinport可以不执行或执行多次

assertEquals(false, winportUrlService.hasWinport(memberId));

assertEquals(false, winportUrlService.hasWinport(memberId));

// 下面的Invocation成功

winportUrlService.getWinportUrlThrowException(memberId);

}

}
 

4、此外,若不指定执行次数,Expections块默认必须执行一次,NonStrictExpections块中的Invocation可执行

N次或不执行;若显式地指定执行次数(N次),二者的Invocation都必须执行N次

JMockit学习笔记的更多相关文章

  1. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  2. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  3. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  4. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  5. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  6. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

  7. CSS学习笔记

    CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...

  8. HTML学习笔记

    HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...

  9. DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记

    今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...

随机推荐

  1. 201871010111-刘佳华《面向对象程序设计(java)》第八周学习总结

    201871010111-刘佳华<面向对象程序设计(java)>第八周学习总结 实验七 接口的定义与使用 实验时间 2019-10-18 第一部分:知识总结 接口的概念: ①java为了克 ...

  2. <Math> 258 43

    258. Add Digits class Solution { public int addDigits(int num) { if(num == 0) return 0; if(num % 9 = ...

  3. vue项目中常见问题及解决方案

    webpack项目中自动引入全局scss变量文件 假设我们有一个公共的scss变量文件variables.scss /*存放所有全局变量*/ $card-title:#C7D200; //首页 卡片标 ...

  4. 探索clickout指令实现

    实现一个可复用的点击区域之外方法 随着3大框架的风靡,我们从以前的layer等UI库迁移到了更加强大的UI库,比如vue的好伙伴element,组件库的作用是封装一些常用的功能,将HTML.CSS.J ...

  5. vue_03day

    目录 作业: vue组件操作页面渲染: 组件渲染: 作业: vue组件操作页面渲染: 1.有以下广告数据(实际数据命名可以略做调整) ad_data = { tv: [ {img: 'img/tv/0 ...

  6. How does Chrome Extension crx Downloader work? ——— From crxdown.com

    How does Chrome Extension crx Downloader work? Home >> blog >> How does Chrome Extension ...

  7. CSS使用知识点

    1.空白符   2.字符间距   3.省略号样式   4.水平垂直居中用法   5.CSS角标实现   空格符 1.  相当于键盘按下的空格,区别是 是可以累加的空格,键盘敲下的空格不会累加 2.  ...

  8. Vue.js 源码分析(二十五) 高级应用 插槽 详解

    我们定义一个组件的时候,可以在组件的某个节点内预留一个位置,当父组件调用该组件的时候可以指定该位置具体的内容,这就是插槽的用法,子组件模板可以通过slot标签(插槽)规定对应的内容放置在哪里,比如: ...

  9. 我在生产项目里是如何使用Redis发布订阅的?(一)使用场景

    转载请注明出处! 导语 Redis是我们很常用的一款nosql数据库产品,我们通常会用Redis来配合关系型数据库一起使用,弥补关系型数据库的不足. 其中,Redis的发布订阅功能也是它的一大亮点.虽 ...

  10. AOP方法拦截获取参数上的注解

    https://www.jianshu.com/p/f5c7417a75f9 获取参数注解 在spring aop中,无论是前置通知的参数JoinPoint,还是环绕通知的参数ProceedingJo ...