Mockito Mock示例
在与Mockito的这一程序中,我们将学习Mockito的核心是什么,令人惊讶的是,嘲笑!
Mock是一个对象,它具有预定义的方法在测试期间执行的方法执行,并记录了这些执行的期望。
创建Mockito Testng示例的步骤。
第1步:创建一个简单的Java Maven项目。
添加到ClassPath,使用Maven
第2步:将Mockito添加到项目的最快方法是使用Maven依赖项。
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.9.5</version> </dependency>
此依赖性足够简单,不会带来任何其他或者冗余库。
请参阅此处获取最新版本的库。
由于我们也将使用一些JUnit函数,我们还需要它是依赖。
让我们添加它,
<!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency>
pom.xml将如下所示:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.igi.theitroad</groupId> <artifactId>MockitoMockExample</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.9.5</version> </dependency> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency> </dependencies> </project>
创造模仿
需要在实际使用之前创建模拟,就像其他任何东西一样。
我们可以在四种单独的方式中使用Mock()方法来创建模拟。
- 模拟(类<T> ClassBeingMocked):此方法使用默认答案设置为返回默认值创建一个给定类的模型。这是测试中最常用的方法。
- 模拟(类<T> ClassBeingMocked,String名称):此方法创建一个带有默认答案设置为返回默认值的给定类的模型。它还为模拟设置了名称。此名称存在于所有验证消息中。这在调试中非常有用,因为它允许我们区分模拟。
- 模拟(类<t> classbeingmocked,答案defaultanswer):此方法创建一个给定类的模型。换句话说,所有非卧式模拟的方法都可以在通过答案中定义。
- 模拟(类<t> classbeingmocked,mocksettings mocksettings):此方法创建具有可自定义模拟设置的给定类的模拟。我们几乎不应该使用该函数。
使用mock()
第3步:让我们说你有一个客户类,你想测试计算客户类的账单方法。
账单计算将取决于购买的商品列表。
我们将使用Mockito的Mock方法实际模拟项目并添加到列表中。
通过这种方式,我们将能够测试计算账单方法,而实际上将实际项目添加到listofitems。
让我们创建一个客户类。
package org.igi.theitroad.mockito;
import java.util.List;
public class Customer {
String name;
List<Item> listOfItems;
public int calculateBill()
{
int total = 0;
for (Item item:listOfItems) {
total+=item.getPrice(item.getName());
}
return total;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Item> getListOfItems() {
return listOfItems;
}
public void setListOfItems(List<Item> listOfItems) {
this.listOfItems = listOfItems;
}
}
创建一个名为Item的接口。
package org.igi.theitroad.mockito;
public interface Item {
String getName();
int getPrice(String name);
}
现在让我们创建一个实际测试客户的计算班方法的测试类。
package org.igi.theitroad.test;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import org.igi.theitroad.mockito.Customer;
import org.igi.theitroad.mockito.Item;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class CustomerBillTest {
Customer c1;
@Before
public void setup(){
c1=new Customer();
c1.setName("John");
List<Item> listOfItems=new ArrayList<Item>();
Item i1=Mockito.mock(Item.class);
Item i2=Mockito.mock(Item.class);
Item i3=Mockito.mock(Item.class);
listOfItems.add(i1);
listOfItems.add(i2);
listOfItems.add(i3);
c1.setListOfItems(listOfItems);
when(i1.getName()).thenReturn("Rice");
when(i2.getName()).thenReturn("Tea");
when(i3.getName()).thenReturn("Wheat");
when(i1.getPrice("Rice")).thenReturn(100);
when(i2.getPrice("Tea")).thenReturn(200);
when(i3.getPrice("Wheat")).thenReturn(300);
}
@Test
public void test_Customer_CalculateBill()
{
int billAmount=c1.calculateBill();
Assert.assertEquals(600, billAmount);
}
}
我们在这里嘲笑了I1,I2和I3,并使用Mockito的时间,然后在GetName和GetPrice方法GetCalled中使用Mockito方法来模拟行为。
第4步:运行程序时,我们将得到以下输出:
另一个例子
使用新关键字实例化对象的代码直接进行测试困难。
通过使用工厂模式,我们将在要测试的代码之外移动对象的创建。
这为我们提供了一个注入模拟对象和/或者模拟工厂的地方。
我们首先创建一个可测试的Foo类和Foofactory实现。
public class Foo {
private int a;
private int b;
//public getters and setters
}
public interface FooFactory {
public Foo create(int x, int y);
}
public class FoofactoryImpl implements Foofactory {
public Foo create(int x, int y) {
Foo foo = new Foo();
foo.setA(x);
foo.setB(y);
return foo;
}
}
现在,我们的测试程序:
public class MyClass {
private final FooFactory fooFactory;
public MyClass(FooFactory fooFactory) {
this.fooFactory = fooFactory;
}
public void doSomething() {
Foo foo = fooFactory.create(100, 101);
//do something with the foo ...
}
}
现在,我们可以在测试中传入模拟工厂,这将创建一个模拟foo或者我们选择的foo。
让我们使用Mockito创建模拟工厂。
public class MyClassTest {
@Test
public void doSomething() {
Foo foo = mock(Foo.class);
//set expectations for foo ...
FooFactory fooFactory = mock(FooFactory.class);
when(fooFactory.create(100, 101)).thenReturn(foo);
MyClass fixture = new MyClass(fooFactory);
fixture.doSomething();
//make assertions ...
}
}
注意:现在,实例化foo的工厂必须能够访问构造函数,因此,不应该私下。
什么是答案?什么时候用它们?
在上面的示例中,我们使用了(......),因为我们只是想返回一个嘲弄的对象i.e.,foo。
但是,如果我们想根据传递给该方法的参数进行一些处理,在我们的情况下创建(100,101)。
thyanswer()vs thenreturn()
答案指定执行的操作以及与模拟互动时返回的返回值。
最简单的示例以使用传递给(...)的参数是返回它。
这只能使用thyanswer(...)完成。
when(mock.myFunction(anyString())).thenAnswer(new Answer<String>() {
@Override
public String answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
return fooFactory.create(args[1], args[0]);
}
});
在上面的示例中,我们获取参数并在交换它们后使用出厂方法使用它在创建Foo实例中。
用不同默认答案的注释
通常,我们将无需为Mockito创建自定义答案,许多人已经捆绑在Mockito中,并且没有必要重新发明轮子。
无论如何你要为什么要创建自定义答案?
让我们来看看几个可能的答案:
- 很可能是为了调试应用程序,我们想记录传递给废物方法的参数。
- 我们希望在传递的参数上执行一些业务逻辑,而不是返回一些固定值。
- 我们希望存根具有回调的异步方法。
如果我们认为它仍然想要创建自定义答案,请检查是否没有Mockito存在。
在提供的Mockito API中,我们可以在"其他ackeswers类"中找到以下答案(检查示例的该类的javadoc):
- returnsfirstarg:此答案将返回调用的第一个参数
- returnssecondarg:此答案返回调用的第二个参数
- returnslastarg:此答案返回调用的最后一个参数
- returnsargat:此答案返回给定索引提供的调用的参数
- Delegatesto:此答案将所有方法委托给委托(实际上,如果该方法尚未停止),则调用委托的方法)

