Mockito六个简单示例(翻译)
2013-12-01
原文地址:Mockito in six easy examples
原文作者:Gojko Adzic
Mockito是个奇妙的Java模拟对象(mock)类库。与其他Java或是.NET模拟对象类库相比,我被它简单、易用的特性所吸引。接下来我会列举六个十分简单的例子来帮助你了解Mockit。
首先,前往主页下载mockito,把org.mockito.Mockito
类import
(或者使用static import
,下文都使用这种方式)进你的代码中,然后开始感受它的奇妙之处吧。
使用mock(class)
来创建一个桩(stub)或者一个模拟对象(译者注:关于桩与模拟的区别可以参考Martin Fowler的文章Mocks Aren’t Stubs)。然后,使用when(mock).thenReturn(value)
来指定这个桩返回的值。如果你指定了不止一个值,这个桩将会顺序返回这些值,直到最后一个将会不变(所以指定一次返回值,这个方法的返回就不会变了)。例如,
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import java.util.Iterator;
import org.junit.Test;
....
@Test
public void iterator_will_return_hello_world(){
//arrange
Iterator i=mock(Iterator.class);
when(i.next()).thenReturn("Hello").thenReturn("World");
//act
String result=i.next()+" "+i.next();
//assert
assertEquals("Hello World", result);
}
在这个例子中,我们创建了一个模拟的迭代器,第一次调用next()
时返回"Hello"
,第二次返回"World"
。接着我们做一个普通的断言(Assertion)。
桩当然也可以根据对方法传递的不同参数返回不同的值。例如,
@Test
public void with_arguments(){
Comparable c=mock(Comparable.class);
when(c.compareTo("Test")).thenReturn(1);
assertEquals(1,c.compareTo("Test"));
}
在上面的例子里,我们创建了一个Comparable
的桩对象,当它和一个特定的值进行比较时(这里是"Test"
)返回1。如果你并不能预测到这个方法将会传递的参数,或者你更不关心参数是什么,可以使用anyInt()
(当然还有其他类型的替代)。举个例子,
@Test
public void with_unspecified_arguments(){
Comparable c=mock(Comparable.class);
when(c.compareTo(anyInt())).thenReturn(-1);
assertEquals(-1,c.compareTo(5));
}
这个Comparable
的桩对象,不管我们传递任何参数,这个方法总是返回-1。如果你的方法是void
型的,这个就有点讨巧了,因为你没法在when中传递这个方法。可以把之前的方式替换成doReturn(result).when(mock_object).void_method_call();
。除了可以指定返回,你还可以使用.thenThrow()
或者doThrow()
。例如,
@Test(expected=IOException.class)
public void OutputStreamWriter_rethrows_an_exception_from_OutputStream()
throws IOException{
OutputStream mock=mock(OutputStream.class);
OutputStreamWriter osw=new OutputStreamWriter(mock);
doThrow(new IOException()).when(mock).close();
osw.close();
}
这个例子中,当我们调用OutputStream
的close
方法时,会抛出IOException
。我们简单地可以验证,OutputStreamWriter
从包装的输出流(译者注,这边的包装对象使用到的是装饰器模式)中重新抛出了这个异常。为了验证相关对象实际的调用(特别被用于模拟对象),我们可以使用verify(mock_object).method.call
。例如,
@Test
public void OutputStreamWriter_Closes_OutputStream_on_Close()
throws IOException{
OutputStream mock=mock(OutputStream.class);
OutputStreamWriter osw=new OutputStreamWriter(mock);
osw.close();
verify(mock).close();
}
这个例子将会验证当OutputStreamWriter
被关闭时,是否同时关闭了包装的输出流。就和之前的那个例子一样,通过使用类似anyInt()
的匹配器来匹配方法中的参数。这边要注意,你不能把文本参数(译者注:直接传递具体的参数值)和匹配器参数混合使用,所以如果你使用了多个参数,同时包含了文本参数或是匹配参数。使用eq(value)
匹配器把文本参数转换为匹配参数来作比较。Mockito内建了许多匹配器,但是有时候你需要灵活使用。例如,OutputStreamWriter
会对输出设置缓冲,直到倾倒缓冲的时候才会使用到包装的输出流对象,但是我们不知道究竟这个缓冲有多大,所以我们不能做等价的匹配。我们需要使用我们自己的匹配:
@Test
public void OutputStreamWriter_Buffers_And_Forwards_To_OutputStream()
throws IOException{
OutputStream mock=mock(OutputStream.class);
OutputStreamWriter osw=new OutputStreamWriter(mock);
osw.write('a');
osw.flush();
// can't do this as we don't know how long the array is going to be
// verify(mock).write(new byte[]{'a'},0,1);
BaseMatcher arrayStartingWithA=new BaseMatcher(){
@Override
public void describeTo(Description description) {
// nothing
}
// check that first character is A
@Override
public boolean matches(Object item) {
byte[] actual=(byte[]) item;
return actual[0]=='a';
}
};
// check that first character of the array is A, and that the other two arguments are 0 and 1
verify(mock).write(argThat(arrayStartingWithA), eq(0),eq(1));
}
就说到这里,这些已经包含了你所需要了解的基础知识。现在开始深入学习,重构你那些丑陋的easymock代码吧。