单元测试之Mockito

关键词:Mockito

以下内容翻译整理自:
Mockito latest documentation
[译] 使用强大的 Mockito 测试框架来测试你的代码

Unit tests with Mockito - Tutorial
When/how to use Mockito Answer(需要翻墙)
使用Mockito对异步方法进行单元测试

2. 使用mock对象进行测试

单元测试应该尽可能隔离其他类或系统的影响。

  • dummy object
  • Fake objects
  • stub class
  • mock object

可以使用mock框架创建mock对象来模拟类,mock框架允许在运行时创建mock对象,并定义它们的行为。
Mockito是目前流行的mock框架,可以配合JUnit使用。Mockito支持创建和设置mock对象。使用Mockito可以显著的简化对那些有外部依赖的类的测试。

  • mock测试代码中的外部依赖
  • 执行测试
  • 验证代码是否执行正确
mockito

4. 使用Mockito API

  • Static imports
    添加static import org.mockito.Mockito.*;

  • Creating and configuring mock objects with Mockito

Mockito支持通过静态方法mock()创建mock对象,也可以使用@Mock注解。如果使用注解的方式,必须初始化mock对象。使用MockitoRule,调用静态方法MockitoAnnotations.initMocks(this)初始化标示的属性字段。

import static org.mockito.Mockito.*;

public class MockitoTest {
    @Mock
    MyDatabase databaseMock;
  
    @Rule
    public MockitoRule mockitoRule = MockitoJUnit.rule();
 
    @Test
    public void testQuery() {
        ClassToTest t = new ClassToTest(databaseMock);
        boolean check = t.query("* from t"); 
        assertTrue(check);
        verify(databaseMock).query("* from t"); 
    }
}
  • Configuring mocks

    • when(…​.).thenReturn(…​.)用于指定条件满足时的返回值,也可以根据不同的传入参数返回不同的值。
    • doReturn(…​).when(…​).methodCall作用类似,但是用于返回值为void的函数。
  • Verify the calls on the mock objects
    Mockito会跟踪mock对象所有的函数调用以及它们的参数,可以用verify()验证
    一个函数有没有被调用with指定的参数。这个被称为"behavior testing"

  • Wrapping Java objects with Spy
    @Spyspy()方法用于封装实际的对象。除非有特殊声明(stub),都会真正的调用对象的方法。

  • Using @InjectMocks for dependency injection via Mockito

    • You also have the @InjectMocks annotation which tries to do constructor, method or field dependency injection based on the type.
  • Capturing the arguments
    ArgumentCaptor允许我们在verification期间访问函数的参数。在捕获这些函数参数后,可以用于测试。

  • Limitations
    以下不能使用Mockito测试
    • final classes
    • anonymous classes
    • primitive types
1. Mockito Answer的使用

A common usage of Answer is to stub asynchronous methods that have callbacks.

doAnswer(new Answer<Void>() {
    public Void answer(InvocationOnMock invocation) {
    Callback callback = (Callback) invocation.getArguments()[0];
    callback.onSuccess(cannedData);
    return null;
    }
}).when(service).get(any(Callback.class));

Answer can also be used to make smarter stubs for synchronous methods.

when(translator.translate(any(String.class))).thenAnswer(reverseMsg())
...
// extracted a method to put a descriptive name
private static Answer<String> reverseMsg() {
    return new Answer<String>() {
        public String answer(InvocationOnMock invocation) {
            return reverseString((String) invocation.getArguments()[0]));
        }
    }
}

Mockito限制

  • final classes
  • anonymous classes
  • primitive types

Mockito示例

1. Let's verify some behaviour!
//Let's import Mockito statically so that the code looks clearer 
import static org.mockito.Mockito.*; 

//mock creation 
List mockedList = mock(List.class); 

//using mock object 
mockedList.add("one"); 
mockedList.clear(); 

//verification 
verify(mockedList).add("one"); 
verify(mockedList).clear();

验证某些操作是否执行

Once created, a mock will remember all interactions. Then you can selectively verify whatever interactions you are interested in.

2. How about some stubbing?
//You can mock concrete classes, not just interfaces 
LinkedList mockedList = mock(LinkedList.class); 

//stubbing 
when(mockedList.get(0)).thenReturn("first"); 
when(mockedList.get(1)).thenThrow(new RuntimeException()); 

//following prints "first" 
System.out.println(mockedList.get(0)); 
//following throws runtime exception 
System.out.println(mockedList.get(1)); 
//following prints "null" because get(999) was not stubbed 
System.out.println(mockedList.get(999)); 

//Although it is possible to verify a stubbed invocation, usually **it's just redundant** 
//If your code cares what get(0) returns, then something else breaks (often even before verify() gets executed). 
//If your code doesn't care what get(0) returns, then it should not be stubbed. Not convinced? See [here](http://monkeyisland.pl/2008/04/26/asking-and-telling). 
verify(mockedList).get(0);

By default, for all methods that return a value, a mock will return either null, a a primitive/primitive wrapper value, or an empty collection, as appropriate. For example 0 for an int/Integer and false for a boolean/Boolean.

3. Argument matchers
//stubbing using built-in anyInt() argument matcher 
when(mockedList.get(anyInt())).thenReturn("element"); 

//stubbing using custom matcher (let's say isValid() returns your own matcher implementation): 
when(mockedList.contains(argThat(isValid()))).thenReturn("element"); 

//following prints "element" 
System.out.println(mockedList.get(999)); 

//**you can also verify using an argument matcher** 
verify(mockedList).get(anyInt()); 

//**argument matchers can also be written as Java 8 Lambdas** 
verify(mockedList).add(someString -> someString.length() > 5);

If you are using argument matchers, all arguments have to be provided by matchers.

5. Stubbing void methods with exceptions
doThrow(new RuntimeException()).when(mockedList).clear(); 

//following throws RuntimeException: 
mockedList.clear();
6. Verification in order
// A. Single mock whose methods must be invoked in a particular order 
List singleMock = mock(List.class); 

//using a single mock 
singleMock.add("was added first"); 
singleMock.add("was added second"); 

//create an inOrder verifier for a single mock 
InOrder inOrder = inOrder(singleMock); 

//following will make sure that add is first called with "was added first, then with "was added second" 
inOrder.verify(singleMock).add("was added first"); 
inOrder.verify(singleMock).add("was added second"); 

// B. Multiple mocks that must be used in a particular order 
List firstMock = mock(List.class); 
List secondMock = mock(List.class); 

//using mocks 
firstMock.add("was called first"); 
secondMock.add("was called second"); 

//create inOrder object passing any mocks that need to be verified in order 
InOrder inOrder = inOrder(firstMock, secondMock); 

//following will make sure that firstMock was called before secondMock 
inOrder.verify(firstMock).add("was called first"); 
inOrder.verify(secondMock).add("was called second"); 

// Oh, and A + B can be mixed together at will
7. Making sure interaction(s) never happened on mock
//using mocks - only mockOne is interacted 
mockOne.add("one"); 

//ordinary verification 
verify(mockOne).add("one"); 

//verify that method was never called on a mock 
verify(mockOne, never()).add("two"); 

//verify that other mocks were not interacted 
verifyZeroInteractions(mockTwo, mockThree);
8. Finding redundant invocations
//using mocks 
mockedList.add("one"); 
mockedList.add("two"); 

verify(mockedList).add("one"); 

//following verification will fail 
verifyNoMoreInteractions(mockedList);

verifyNoMoreInteractions() is a handy assertion from the interaction testing toolkit. Use it only when it's relevant. Abusing it leads to overspecified, less maintainable tests.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容

  • 在博客Android单元测试之JUnit4中,我们简单地介绍了:什么是单元测试,为什么要用单元测试,并展示了一个简...
    水木飞雪阅读 9,080评论 4 18
  • 背景 在写单元测试的过程中,一个很普遍的问题是,要测试的目标类会有很多依赖,这些依赖的类/对象/资源又会有别的依赖...
    johnnycmj阅读 1,113评论 0 3
  • 什么是Mock? 在单元测试中,我们往往想去独立地去测一个类中的某个方法,但是这个类可不是独立的,它会去调用一些其...
    健谈的Boris阅读 22,298评论 0 14
  • 什么是 Mock mock 的中文译为: 仿制的,模拟的,虚假的。对于测试框架来说,即构造出一个模拟/虚假的对象,...
    Whyn阅读 4,210评论 0 3
  • 写在前面 因个人能力有限,可能会出现理解错误的地方,欢迎指正和交流! 关于单元测试 通常一个优秀的开源框架,一般都...
    汪海游龙阅读 2,820评论 0 21