Mockito.eq 匹配器似乎与列表引用匹配,而不是值



我在类App中有一个方法addToClonedList(List),它调用类Dependency中的方法add(List)。 我想对addToClonedList(List)进行单元测试,并且我想创建一个模拟Dependency对象(称为mockDependency)并验证是否使用正确的参数调用了方法mockDependency.add(List)。 然而,由于clonedList引用的List实例在有问题的调用后添加了一个新元素(100),Mockito认为2元素List被传递给了mockDependency,并且测试失败。 实际上,传递给mockDependency.add(List)List在调用时只包含一个元素。 这是预期的莫米托行为吗? 有没有更标准的方法来测试我是否通过了正确的ListmockDependency.add(List)

请参阅下面的代码结构和测试输出:

main/java/App.java:

import java.util.*;
public class App {
Dependency dataLayer = new Dependency();
void addToClonedList(List<Integer> integerList) {
List<Integer> clonedList = new ArrayList<Integer>(integerList);
dataLayer.add(clonedList);
clonedList.add(100);
}
}

main/java/Dependency.java:

import java.util.List;
public class Dependency {
void add(List<Integer> integerList) {
//
}
}

test/java/AppTest.java:

import java.util.*;
import org.junit.*;
import org.mockito.*;
public class AppTest {
@InjectMocks
App app;
@Mock
Dependency mockDependency;
@Before
public void beforeEachTest() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testWithVerify() {
List<Integer> originalList = new ArrayList<>();
originalList.add(1);
app.addToClonedList(originalList);
Mockito.verify(mockDependency).add(Mockito.eq(originalList));
}
}

绒球.xml:

<?xml version="1.0" encoding="UTF-8"?>
<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>com.athenahealth</groupId>
<artifactId>mockitotest</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.testifyproject.mock</groupId>
<artifactId>mockito</artifactId>
<version>0.9.8</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
</project>

测试输出:

Argument(s) are different! Wanted:
mockDependency.add([1]);
-> at AppTest.testWithVerify(AppTest.java:25)
Actual invocation has different arguments:
mockDependency.add([1, 100]);
-> at App.addToClonedList(App.java:8)
Comparison Failure: 
Expected :mockDependency.add([1]);
Actual   :mockDependency.add([1, 100]);

正如Andy Turner所指出的,问题在于Mockito只保留对传递的值的引用,而不克隆它。这是有道理的,因为对于像 String 这样的不可变值对象来说,这是浪费的,而对于像 Thread 这样的某些引用来说

,这几乎是不可能的。但是,您可以编写自己的答案来自己制作副本:

List<Integer> listSnapshot;
@Test
public void testWithVerify() {
List<Integer> originalList = new ArrayList<>();
originalList.add(1);
Mockito.when(mockDependency.add(any())).thenAnswer(invocation => {
listSnapshot = new ArrayList<>((List<Integer>) (invocation.getArguments()[0]));
});
app.addToClonedList(originalList);
assertEquals(originalList, listSnapshot);
}

Mockito并不神奇。

当在模拟上调用add方法时,模拟只是保留对参数值的引用。然后,eq匹配器进行比较,以查看您传入verify的参数是否等于该值,使用equals。它不能做得比这更好,因为一般来说,它不知道如何获取参数的副本。

如果您之后修改传递到模拟中的值,Mockito 不知道您已经这样做了,并且仍然只是使用equals比较两个引用。

你用clonedList在模拟上调用该方法,然后在clonedList中添加一个值,但不integerList。因此,当您将clonedList与使用eqoriginalList进行比较时,它们是不同的,因此检查不会通过。

正如建议的那样,如果您不添加到clonedList,则测试通过;然后您可以看到它不是通过将eq替换为same来比较使用==(然后测试将失败)。

相关内容

  • 没有找到相关文章

最新更新