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:此答案将所有方法委托给委托(实际上,如果该方法尚未停止),则调用委托的方法)