Aar*_*ron 8 java unit-testing reference list mockito
我在类addToClonedList(List)
中有一个方法App
调用add(List)
类中的方法Dependency
。我想要进行单元测试addToClonedList(List)
,并且想要创建一个模拟Dependency
对象(称为)并验证是否使用正确的参数调用mockDependency
该方法。mockDependency.add(List)
但是,由于List
引用的实例在相关调用之后clonedList
将一个新元素 ( 100
) 添加到 if ,因此 Mockito 认为 2 元素List
已传递给mockDependency
,并且测试失败。实际上,调用时List
传递给的仅包含一个元素。mockDependency.add(List)
这是预期的 Mockito 行为吗?有没有更标准的方法来测试我已经通过了正确的List
方法mockDependency.add(List)
?
请参阅下面的代码结构和测试输出:
主/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);
}
}
Run Code Online (Sandbox Code Playgroud)
主/java/Dependency.java:
import java.util.List;
public class Dependency {
void add(List<Integer> integerList) {
//
}
}
Run Code Online (Sandbox Code Playgroud)
测试/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));
}
}
Run Code Online (Sandbox Code Playgroud)
pom.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>
Run Code Online (Sandbox Code Playgroud)
测试输出:
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]);
Run Code Online (Sandbox Code Playgroud)
正如 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);
}
Run Code Online (Sandbox Code Playgroud)