Mockito Mock示例

时间:2020-02-23 14:35:28  来源:igfitidea点击:

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