在编写代码测试用例时,Mockito是开发人员最常见的选择之一。 然后我们面对的问题是,如何使用Mockito的thenReturn()和thenAnswer()方法? 如果您也面临这个问题,请不要担心每个人都面临或已经遇到了这个问题,我们将在这里解决!! 所以,开始吧...
Mockito是最著名的测试模拟框架之一。 让我们假设您已经了解了模仿。 如果没有,您可以在我们继续之前访问官方的Mockito网站 。
在调用真实方法的Mockito方法中,您可以指定调用该方法时要返回的内容或执行的操作。 这称为“模拟”。 有多种方法可以指定模拟行为。 最常见的方法是使用thenReturn()和thenAnswer()方法。
大多数时候,使用thenReturn ()(很好),但有时我们需要使用thenAnswer ()。
什么时候应该使用thenReturn,什么时候可以回答?
最简单的答案是–如果在方法调用中需要固定的返回值,则应使用thenReturn(…)。 如果需要执行某些操作或需要在运行时计算值,则应使用thenAnswer(…)
让我们看看例子
假设我们需要在getName()方法调用中返回字符串值“ Mockito”。
Mockito.when(mock.getName() ).thenReturn(“Mockito”)
如果在调用getCurrentTime方法时需要返回系统时间,则需要
Mockito.when (mock.getCurrentTime() ).thenAnswer(I -> new Date() );
现在让我们详细介绍
方法thenReturn()需要一个固定的对象,该对象将在我们调用该方法时返回。 我们可以传递任何类型的对象或值,方法调用将返回相同的值。
Syntax: OngoingStubbing<T> thenReturn(T value);
thenAnswer方法需要实现接口org.mockito.stubbing.Answer的类的对象。
Answer是具有方法answer(..)的功能接口。 当我们从模拟对象中调用模拟方法时,将调用answer()方法。 我们可以使用Java 8 lambda功能来实现answer方法。
Syntax: OngoingStubbing<T> thenAnswer(Answer<?> answer);
两者之间的基本区别是thenRetun()将始终返回同一对象。
每当我们调用模拟方法时,thenAnswer方法都会从对象中调用该方法。
我们还可以将函数传递给thenRetun()来定义返回值。
当我们使用带功能的thenAnswer或thenRetun时,可能有两种情况。
- 如果函数具有固定的返回值 ,则结果将没有差异,例如。 thenReturn(getUserName()); 然后Answer(I-> getUserName()); 功能类似
- 如果根据某些参数在运行时计算返回值 ,则可能会有不同的结果,例如。 thenReturn(getCurrentTime()); 然后Answer(I-> getCurrentTime());
(I)函数返回固定值时
让我们看下面的示例,我们有一个方法getName()在用户类中进行测试。
我们将创建一个UserTest类进行测试。 然后,我们将模拟getName()方法。
Public class User {
public String getName() {
return this .name;
} }
// This is the test class which will test the User class public class UserTest {
private String dummyName() {
System.out.println( " #dummyName called" );
return "Java" ;
} @Test public void thenReturnTest() throws Exception {
Tester mock = Mockito.mock(User. class );
System.out.println( "------ Using: thenReturn------ " );
Mockito.when(mock.getName()).thenReturn(dummyName());
System.out.println( " -- method calls" );
System.out.println( "Call.1 : " + mock.getName());
System.out.println( "Call.2 : " + mock.getName());
} @Test public void thenAnswerTest() throws Exception {
Tester mock = Mockito.mock(User. class );
System.out.println( "------ Using: thenAnswer------ " );
Mockito.when(mock.getName()).thenAnswer(i -> dummyName());
System.out.println( " -- method calls" );
System.out.println( "Call.1 : " + mock.getName());
System.out.println( "Call.2 : " + mock.getName());
} }
//输出:
—— Using: thenReturn——
— #dummyName called
— method calls
Call.1 : Java
Call.2 : Java
—— Using: thenAnswer——
— method calls
— #dummyName called
Call.1 : Java
— #dummyName called
Call.2 : Java
在上面的示例中,我们可以看到在两种情况下getName()方法都返回相同的值。 但是,打印的消息是不同的。
如果使用thenRetun() ,请在实际调用之前执行 dummyName() 方法 。
这是因为如上所述,那么thenReturn()需要值,因此在初始化时将执行它并使用返回值。
如果thenAnswer(),则#dummyName调用也会打印两次。 这是因为每次我们调用模拟方法时,都会执行该函数。
(II)在运行时计算返回值
让我们看下面的示例,我们有一个方法getTime()在用户类中进行测试。
我们将创建一个UserTest类进行测试。 然后将模拟getTime()方法。
Public class User {
public String getTime() {
return this . time ;
} } public class UserTest {
private String now() {
Calendar now = Calendar.getInstance();
return now.get(Calendar.MINUTE) + " : " + now.get(Calendar.SECOND);
}
private String dummyGetTime() {
System.out.println( " #getTime called" );
return now();
} @Test public void thenReturnTest() throws Exception {
Tester mock = Mockito.mock(User. class );
System.out.println( "------ Using: thenReturn------ " );
Mockito.when(mock.getTime()).thenReturn(dummyGetTime());
System.out.println( " -- method calls" );
System.out.println( "Call.1> " + mock.getTime()+ " called at - " +now); " called at - " +now);
TimeUnit.SECONDS.sleep(5);
System.out.println( "Call.2> " + mock.getTime()+ " called at - " +now);
} @Test public void thenAnswerTest() throws Exception {
Tester mock = Mockito.mock(User. class );
System.out.println( "------ Using: thenAnswer------ " );
Mockito.when(mock.getTime()).thenAnswer(i -> dummyGetTime());
System.out.println( " -- method calls" );
System.out.println( "Call.1> " + mock.getTime()+ " called at : " +now);
TimeUnit.SECONDS.sleep(5);
System.out.println( "Call.2> " + mock.getTime()+ " called at : " +now);
} }
//输出:>
—— Using: thenReturn——
— #getTime called
— method calls
Call.1> 4 : 22 called at- 4 : 22
Call.2> 4 : 22 called at- 4 : 27
—— Using: thenAnswer——
— method calls
— #getTime called
Call.1> 4 : 22 called at- 4 : 22
— #getTime called
Call.2> 4 : 27 called at- 4 : 27
在上面的示例中,我们可以看到,在thenAnswer()情况下,getTime()方法返回不同的值,而在thenRetun()情况下,返回相同的值。
在thenRetun()的情况下,该值是从now()方法(即4:22)计算得出的。 每次调用getTime()函数时,thenReturn()方法中都会使用此值。
在thenAnswer()的情况下,每次我们调用模拟方法getTime()时,也会调用now()方法并返回新值。
绩效影响
如果该方法返回简单的固定值,我们可能看不到任何性能差异。 但是,如果该方法具有数据库或网络调用,则可能会有很大的性能差异。
如果value是固定的,那么我们最好使用thenReturn(),因为它只会执行一次。
结论
我们可以得出结论,thenReturn()始终返回相同的值,而thenAnswer()返回实时计算的值。
快速阅读
- 如果在方法调用中需要固定的返回值,则应使用thenReturn(...)
- 如果在运行时计算值,则应使用thenAnswer(...)
- thenReturn(T value)方法需要固定值,该值将返回
- thenAnswer(Answer <T> answer)需要Answer接口的实例,该接口的answer()方法每次都被调用
- 对于固定的返回值,则可以使用Return()
翻译自: https://www.javacodegeeks.com/2020/05/mockito-thenreturn-vs-mockito-thenanswer.html