将模拟对象添加到Mockito间谍列表<>

时间:2019-04-16 17:30:27

标签: java unit-testing junit mockito

不能将Mockito Spy列表对象包含添加到其中的其他Mock对象?除了创建实际对象之外,还有其他选择吗?

我有一个间谍清单对象

Class TestableClassTest {
@InjectMocks
TestableClass myClassUnderTest;

@Mock
MyService myService
@Spy
List<MyBusinessClass> myBusinessClasses;
@Mock 
MyBusinessClass myBusinessClass1;
@Mock
MyBusinessClass myBusinessClass2;

ResponseEntity result;

@Rule
MockitoRule rule = MockitoJunit.rule();

@Before
public void setup()
{
  myBusinessClasses.add(myBusinessClass1);
  myBusinessClasses.add(myBusinessClass2);
  when(myService.get()).thenReturn(myBusinessClasses);
  result = myClassUnderTest.testThisMethod();
}
 @Test
  public void resultIsReceivedWithNoException()
  { Assert.assertNotNull(result);}
}

但这会在执行此操作时返回nullpointer异常

List<MyBusinessClass> list = someService.get(); MyBusinessClass 
myBusinessClass = list.get(0);// this is null

仅当我从myBusinessClass1创建真实的对象myBusinessClass2MyBusinessClass并将其添加到spy()列表中时,此方法才有效。我的意思是,如果我使用MyBusinessClass myBusinessClass1 = new MyBusinessClass()创建对象,然后将其添加到列表中,我将不再得到null。

编辑: 因此,在单元测试一个类时,我的问题是我们从一个模拟的类的get()方法返回一个列表。如何将一些实际的具体数据放入该列表中,以便我的Class Method which I am testing可以在该数据上工作,然后可以测试我的方法在该数据上正确工作。

3 个答案:

答案 0 :(得分:2)

  

所以,在单元测试一个类时,我的问题是我们从一个模拟的类的get()方法返回一个列表。如何将一些实际的具体数据放入该列表中,以便我正在测试的类方法可以在该数据上工作,然后可以测试我的方法在该数据上可以正常工作。

考虑到MyBusinessClass是一个真正的依赖项,提供了一些业务逻辑,该逻辑具有自己的单元测试,方法如下:

@Mock
MyService myService

List<MyBusinessClass> myBusinessClasses = new ArrayList<>();
@Mock 
MyBusinessClass myBusinessClass1;
@Mock
MyBusinessClass myBusinessClass2;

@Before
public void setup()
{
myBusinessClasses.add(myBusinessClass1);
myBusinessClasses.add(myBusinessClass2);
when(myService.get()).thenReturn(myBusinessClasses);
}

@Test
public void callSomeMethodOnReturnedEntries(){
    new CodeUnderTest(myService).publicInterfaceMethod();

    verify(myBusinessClass1).expectedMethodCall();
    verify(myBusinessClass2).expectedMethodCall();
}

答案 1 :(得分:1)

这里:

@Spy
List<MyBusinessClass> myBusinessClasses;

真的没有任何意义。间谍可以对“间谍”对象进行部分模拟。因此,您有时可以调用“真实”方法,并防止其他方法被调用。有关为什么/如何使用Mockito间谍的说明,请参见here

但是您真的不应该对List对象执行此操作。列表只是容器。当您进行单元测试并且必须控制List实例时,只需将所需的对象放入该List中即可。您不需要嘲笑或间谍清单。您只需创建一些列表实例,然后将要包含的对象放入其中。

因此,真实点是:您必须确保如何获得someService.get();以返回具有已知内容的列表。但是,除非您相应地更新您的问题,否则我们无法提供帮助。

答案 2 :(得分:0)

  

我以前的主角曾经说过什么都不应该是真实的物体

在这种情况下,您还可以模拟(而不是监视)集合,而必须指定其简单行为:

@Mock
MyService myService
@Mock
List<MyBusinessClass> myBusinessClasses;
@Mock 
MyBusinessClass myBusinessClass1;
@Mock
MyBusinessClass myBusinessClass2;

@Before
public void setup()
{
myBusinessClasses.add(myBusinessClass1);
myBusinessClasses.add(myBusinessClass2);

when(myBusinessClasses.size()).thenReturn(2);
when(myBusinessClasses.get(0)).thenReturn(myBusinessClass1);
when(myBusinessClasses.get(1)).thenReturn(myBusinessClass2);

when(myService.get()).thenReturn(myBusinessClasses);
}

@Test
public void callSomeMethodOnReturnedEntries(){
    new CodeUnderTest(myService).publicInterfaceMethod();

    verify(myBusinessClass1).expectedMethodCall();
    verify(myBusinessClass2).expectedMethodCall();
}

我个人会叫达达 overkill

关闭主题

这将导致不好的单元测试,因为它依赖于某些实现细节
生产代码访问该列表中元素的方式。

如果您决定将此实现细节更改为使用列表的迭代器或collections stream API,则必须更改此单元测试以采用新的实现。

真正的坏处是,在这种情况下,该测试不能不能证明您对更改元素访问权限的重构没有改变所需的业务行为。

相关问题