Mockito简介
Mock是单元测试工具的简称,Mock可以理解为模拟对象。
在传统的JUnit单元测试中,我们没有消除在测试中对对象的依赖。如存在A对象方法依赖B对象方法,在测试A对象的时候,我们需要构造出B对象,这样子增加了测试的难度,或者使得我们对某些类的测试无法实现。这与单元测试的思路相违背。
Mockito是一个Java开源的测试框架,Mockito在测试中尝试移除我们传统JUnit单元测试中使用的Expect方式,这样子有效降低代码的耦合。使得我们只测试我们需要的方法和类,而不需过多的考虑依赖类。
Mockito的简单使用
在使用Mockito之前,我们需要下载和在我们工程中引入Jar包。
我们根据官方的入门文档,首先开始对一个List的基本测试。代码如下:
package com
.jing
.mockito
.listTest
;
import java
.util
.
List
;
import org
.junit
.Before
;
import org
.junit
.Test
;
import static org
.mockito
.Mockito
.*;
/**
* 简单使用Mockito对List的部分方法模拟测试
* @author jinglongjun
*
*/
public
class ListTest
{
private List
<String
>
list
;
@SuppressWarnings
(
"unchecked"
)
@Before
public void setUp
(
)
{
list
= mock
(
List
.
class
)
;
}
@Test
public void testAdd
(
)
{
list
.add
(
"one"
)
;
list
.clear
(
)
;
verify
(
list
)
.add
(
"one"
)
;
verify
(
list
)
.clear
(
)
;
}
}
具体代码也可以查看官方文档:http://mockito.org/
Mockito的 Stub基本使用
下面我们模拟一个Dao,以及Service的组合调用。代码参考:http://www.oschina.net/translate/mockito-a-great-mock-framework-for-java-development
public
class Person
{
private Long id
;
private int age
;
private String name
;
package com
.jing
.mockito
.dao
;
public
interface IPersonDao
{
int deletePerson
(Long id
)
;
}
package com
.jing
.mockito
.service
;
import java
.util
.
List
;
public
interface IPersonService
{
/**
* 根据ID删除用户
*
* @param id
* @return
*/
public int deletePersonById
(Long id
)
;
public
class PersonService implements IPersonService
{
IPersonDao personDao
;
@Override
public int deletePersonById
(Long id
)
{
int result
=
0
;
try
{
result
= personDao
.deletePerson
(id
)
;
}catch
(Exception e
)
{
e
.printStackTrace
(
)
;
}
return result
;
}
我们首先模拟对delte方法的简单测试。
package com
.jing
.mockito
.service
;
import org
.junit
.Before
;
import org
.junit
.Test
;
import org
.mockito
.Mockito
;
import com
.jing
.mockito
.dao
.IPersonDao
;
public
class PersonServiceTest
{
private PersonService personService
;
@Before
public void setup
(
)
{
//Mock出对应的对象
personService
= Mockito
.mock
(PersonService
.
class
)
;
personService
.personDao
= Mockito
.mock
(IPersonDao
.
class
)
;
}
@Test
public void deletePersonSuccess
(
)
{
Mockito
.when
(personService
.deletePersonById
(1000L
)
)
.thenReturn
(
1
)
;
}
}
以上代码只是简单的对delete方法测试,相对而言,代码的耦合度还是比较低。
从以上低耦合的代码中,我们可以看到Mockito在单元测试中的一个基本使用,即Stub(存根)。Stub就是把需要测试的数据塞进对象中,使用基本为
Mockito
.when
(
...
)
.thenReturn
(
...
)
;
使用Stub使我们只关注于方法调用和放回结果。一个方法被Stub后,该方法就只返回该结果。对此我们需要注意:
-1,static ,final方法,无法进行Stub操作。
-2,当连续为一个方法Stub时,只会调用最近的一次。
如下测试代码:
@Test
public void testStub
(
)
{
when
(
list
.get
(
0
)
)
.thenReturn
(
"a"
)
;
Assert
.assertEquals
(
"a"
,
list
.get
(
0
)
)
;
when
(
list
.get
(
0
)
)
.thenReturn
(
"a"
)
;
when
(
list
.get
(
0
)
)
.thenReturn
(
"b"
)
;
Assert
.assertEquals
(
"b"
,
list
.get
(
0
)
)
;
}
对于返回值为void的方法,我们也可以Stub,不过不是调用thenReturn而已。
@Test
public void testStubVoid
(
)
{
//1.使用doNothing来调用返回值为空的add方法。
doNothing
(
)
.when
(
list
)
.add
(
0
,
"a"
)
;
//2,直接调用notify
when
(
list
)
.notify
(
)
;
}
在Stub时候,我们可以对方法抛出异常。
@Test
public void testThrowsException
(
)
{
//1,调用add方法时,抛出异常
when
(
list
.add
(
"a"
)
)
.thenThrow
(
new RuntimeException
(
)
)
;
list
.add
(
"a"
)
;
//2,空方法抛出异常
doThrow
(
new RuntimeException
(
)
)
.when
(
list
)
.add
(
0
,
"a"
)
;
list
.add
(
0
,
"a"
)
;
//3,连续调用。第一次调用方法时什么都不做,第二次调用时,抛出异常
doNothing
(
)
.doThrow
(
new RuntimeException
(
)
)
.when
(
list
)
.add
(
0
,
"a"
)
;
list
.add
(
0
,
"a"
)
;
list
.add
(
0
,
"a"
)
;
}
我们运行测试可以发现,在Stub对应方法后,方法如我们期望,在调用时抛出了异常。
参考内容:
http://blog.csdn.net/zhangxin09/article/details/42422643
http://qiuguo0205.iteye.com/blog/1443344
http://www.oschina.net/translate/mockito-a-great-mock-framework-for-java-development