import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class MockSpy {
@Mock
private List<String> mockList;
@Spy
private List<String> spyList = new ArrayList();
@Test
public void testMockList() {
//by default, calling the methods of mock object will do nothing
mockList.add("test");
Mockito.verify(mockList).add("test");
assertEquals(0, mockList.size());
assertNull(mockList.get(0));
}
@Test
public void testSpyList() {
//spy object will call the real method when not stub
spyList.add("test");
Mockito.verify(spyList).add("test");
assertEquals(1, spyList.size());
assertEquals("test", spyList.get(0));
}
@Test
public void testMockWithStub() {
//try stubbing a method
String expected = "Mock 100";
when(mockList.get(100)).thenReturn(expected);
assertEquals(expected, mockList.get(100));
}
@Test
public void testSpyWithStub() {
//stubbing a spy method will result the same as the mock object
String expected = "Spy 100";
//take note of using doReturn instead of when
doReturn(expected).when(spyList).get(100);
assertEquals(expected, spyList.get(100));
}
}
@RunWith(MockitoJUnitRunner.class)
public class ELectionOfYear20XX_Test {
@Mock
VotersOfBelow21 votersOfBelow21;
@Mock
VotersOfAbove21 votersOfAbove21;
@InjectMocks
ElectionOfYear20XX electionOfYear20XX;
@Test
public void testElectionResults(){
Assert.assertEquals(true,electionOfYear20XX.weElected("No Choice"));
}
}
这应输出仅逻辑测试结果,即外部检查:
We elected President Trump
We elected President Trump
使用@Spy进行外部测试,以及使用实际方法调用进行内部测试。
@RunWith(MockitoJUnitRunner.class)
public class ELectionOfYear20XX_Test {
@Spy
VotersOfBelow21 votersOfBelow21;
@Spy
VotersOfAbove21 votersOfAbove21;
@InjectMocks
ElectionOfYear20XX electionOfYear20XX;
@Test
public void testElectionResults(){
Assert.assertEquals(true,electionOfYear20XX.weElected("No Choice"));
}
}
输出:
Voters of above 21 has no Choice Than Thrump in 20XX
We elected President Trump
Voters of below 21 has no Choice Than Thrump in 20XX
We elected President Trump
private final String testEmail = "randomuser@domain.com";
private final String success = "SUCCESS";
@Mock EmailService emailService;
@Spy EmailService emailServiceSpy;
测试项目:
@Test
@Description("When mock is called, we can return any response we like")
public void simpleTest1() {
when(emailService.sendMail(testEmail)).thenReturn(success);
assertEquals(success, emailService.sendMail(testEmail));
}
@Test
@Description("When mock is called but not stubbed, we receive a null value")
public void simpleTest2() {
assertNull(emailService.sendMail(testEmail));
}
@Test
@Description("When a spy is called but not stubbed, the concrete impl is called")
public void simpleTest3() {
assertTrue(emailServiceSpy.sendMail(testEmail).contains(testEmail));
}
@Test
@Description("When a spy is called and stubbed, stubbed value is returned")
public void simpleTest4() {
when(emailServiceSpy.sendMail(testEmail)).thenReturn(success);
assertEquals(success, emailServiceSpy.sendMail(testEmail));
}
9条答案
按热度按时间ymzxtsji1#
从技术上讲,“模拟”和“间谍”都是一种特殊的“测试替身”。
不幸的是,Mockito让这种区别变得很奇怪。
mockito中的mock是其他mock框架中的普通mock(允许您存根调用;即从方法调用中返回特定值)。
mockito中的spy是其他模拟框架中的部分模拟(对象的一部分将被模拟,一部分将使用真正的方法调用)。
0wi1tuuw2#
两者都可以用来模拟方法或字段。不同的是,在模拟中,你创建了一个完整的模拟或伪对象,而在间谍中,有一个真正的对象,你只是间谍或存根它的特定方法。
当然,在spy对象中,由于它是一个真正的方法,当你不存根方法时,它将调用真正的方法行为。如果你想改变和模拟方法,那么你需要存根它。
请将下面的示例作为比较。
什么时候应该使用mock或spy?如果你想安全,避免调用外部服务,只想测试单元内部的逻辑,那么就使用mock。如果你想调用外部服务,执行真正依赖的调用,或者简单地说,你想运行程序,只是存根特定的方法,那么就使用spy。这就是mockito中spy和mock的区别。
cwxwcias3#
简而言之:
@Spy
和@Mock
在代码测试中被大量使用,但是开发人员在使用它们中的一个的情况下确实会混淆,因此开发人员最终使用@Mock
是安全的。@Mock
。@Spy
。下面是我在美国Election 20 xx的场景的例子。
选民可以按照
VotersOfBelow21
和VotersOfABove21
进行划分。理想的出口民调显示,特朗普将赢得选举,因为
VotersOfBelow21
和VotersOfABove21
都将投票给特朗普,说“我们选举了特朗普总统“但这不是真实的场景:
这两个年龄段的选民都投票给了特朗普,因为除了特朗普,他们没有其他有效的选择。
如何测试它
第一个
请注意,在上面的前两类中,这两个年龄组的人都说他们没有比特朗普更好的选择。这明确地意味着他们投票给特朗普只是因为他们别无选择。
现在
ElectionOfYear20XX
说特朗普赢了,因为两个年龄组都以压倒性优势投票给他。如果我们用@Mock来测试
ElectionOfYear20XX
,那么我们可能无法得到特朗普获胜的真正原因,我们将只是测试外部原因。如果我们用@Spy测试
ElectionOfYear20XX
,那么我们就用外部出口民调结果,即内部+外部,得到了特朗普获胜的真正原因。我们的
ELectionOfYear20XX_Test
类:这应输出仅逻辑测试结果,即外部检查:
使用
@Spy
进行外部测试,以及使用实际方法调用进行内部测试。输出:
zynd9foi4#
TL;DR版本,
使用mock,它将为您创建一个基本shell示例。
使用spy,您可以部分模拟现有示例
Spy的典型使用情形:类有一个参数化的构造函数,那么您需要首先创建对象。
am46iovg5#
我在这里创建了一个runable示例https://www.surasint.com/mockito-with-spy/
我抄了一些在这里。
如果您有类似以下代码的内容:
你可能不需要间谍,因为你可以只模仿存款和取款服务。
但是对于一些遗留代码,依赖关系在代码中是这样的:
是的,你可以改到第一个代码,但是API会随之改变。如果这个方法被很多地方使用,你必须全部改变。
另一种方法是,您可以像这样提取依赖关系:
然后可以使用spy注入依赖项,如下所示:
更多详情请点击上面的链接。
j0pj023g6#
最好的起点可能是the docs for mockito。
一般来说,mockito mock允许您创建存根。
例如,如果一个stub方法执行一个开销很大的操作,你就需要创建一个stub方法。比如说,它获取一个数据库连接,从数据库中检索一个值,然后将其返回给调用者。获取数据库连接可能需要30秒,这会减慢你的测试执行速度,以至于你可能会进行上下文切换(或者停止运行测试)。
如果您正在测试的逻辑不关心数据库连接,那么您可以用一个返回硬编码值的stub来替换该方法。
mockito spy可以让你检查一个方法是否调用了其他方法。这在尝试测试遗留代码时非常有用。
如果你在测试一个可以通过副作用来工作的方法,那么你可以使用mockito spy。它将调用委托给真实的对象,并允许你验证方法调用,调用的次数等等。
slwdgvem7#
mock用于模拟一个类的 * 所有 * 方法。
spy用于模拟 * 某些 * 方法,对于其余方法,必须进行实际调用。
kpbwa7wx8#
我喜欢这个建议的简洁性:
来源:https://javapointers.com/tutorial/difference-between-spy-and-mock-in-mockito/
一个共同的区别是:
fivyi3re9#
这个节目有点晚了,但是我觉得其他的回答并没有很好地说明间谍和模仿之间的区别。
给定要测试的服务
我们现在可以用四种不同的场景进行一些测试。
1.呼叫并停止模拟
1.调用模拟而不存根
1.不打电话就能叫间谍
1.打电话干掉一个间谍
设定:
测试项目:
Mock如果没有被stubbed,将返回一个null值,而Spy如果没有被stubbed,将调用具体类内部的实现方法。