使用“this”关键字调用的 Mockito 存根方法

Posted

技术标签:

【中文标题】使用“this”关键字调用的 Mockito 存根方法【英文标题】:Mockito stub method invoked using 'this' keyword 【发布时间】:2017-04-19 20:25:37 【问题描述】:

我必须测试一些 SLSB 的方法,它在当前对象上调用另一个方法(使用 this 关键字),我需要以某种方式存根。

考虑以下简化代码:

@Local
public interface SomeService
    public int someMethod();
    public int anotherMethod();


@Stateless()
public class SomeServiceImpl

    @EJB
    private SomeDAO sDAO;

    public SomeServiceImpl()

    public SomeServiceImpl(SomeDAO sDAO)
         this.sDAO = sDAO;
    

    @Override
    public int someMethod()
        int dbValue = sDAO.getSomeDBValue(); // 1st stub required here
        return dbValue + this.anotherMethod(); // 2nd stub required here
    

    @Override
    public int anotherMethod()
         return 5;
    

要存根 getSomeDBValue() 方法,我可以使用 @Mock 和 @InjectMocks 注释向此类注入模拟,但我不知道如何正确存根 anotherMethod()。要存根它,我肯定需要在模拟对象上进行,所以我尝试将当前对象的引用作为参数传递,并且在测试中只传递模拟对象。 例如,如果我的方法看起来像这样(不需要存根 DAO 方法)..

@Override
public int someMethod(SomeServiceImpl sS) 
    return sS.anotherMethod(); 

我使用手动创建的模拟进行的测试如下所示:

@Test
public void someMethodTest() throws Exception 
    SomeServiceImpl sS = mock(SomeServiceImpl.class);
    when(sS.someMethod(any(SomeServiceImpl.class))).thenCallRealMethod();
    when(sS.anotherMethod()).thenReturn(5);
    assertEquals(5, sS.someMethod(sS));

在模拟对象上调用方法,对对象本身的引用作为参数传递,另一个方法被存根。它有效,但它似乎非常丑陋的解决方案,如果需要使用这样的注释注入我的 DAO 模拟怎么办:

@RunWith(MockitoJUnitRunner.class)
public class SomeClassTest

    @Mock
    SomeDAO sDAO;

    //@Mock //I can't use those 2 annotations at once
    @InjectMocks
    SomeServiceImpl sS; 

    @Test
    public void someMethodTest() throws Exception 
        //...   
    

据我了解,@InjectMocks 注释用于指示应注入带有 @Mock 注释的模拟的类,但对于我丑陋的解决方案,我也需要 SomeServiceImpl 进行模拟。

我的解决方案是否接近正确?我应该如何存根 anotherMethod() 以正确测试 someMethod()?传递类的模拟实例是一个好主意,我在方法参数中测试哪个方法?如果是,我应该如何处理创建带有注释的模拟?

【问题讨论】:

在待测对象上使用Mockito.spy 包装器。 【参考方案1】:

您不应该在 同一个 类上测试另一个方法时模拟 一个 方法。理论上你可以做到这一点(使用 Mokito spy 例如)。

从这个意义上说,您在错误的层面上处理了这个问题:您实际上不应该关心您的测试方法在您的测试类中调用了哪些其他方法。你看,你想测试 someMethod() 确实履行了它的合同。如果这需要在您的生产环境中调用anotherMethod()...当它模拟anotherMethod() 时,您的单元测试有多大价值呢?!

另一个想法:你分离关注点,并将anotherMethod() 部分移动到它自己的类 X 中。然后你的测试类可以保存 X 的实例;然后可以模拟该实例。

【讨论】:

以上是关于使用“this”关键字调用的 Mockito 存根方法的主要内容,如果未能解决你的问题,请参考以下文章

Mockito - 存根方法时出现 NullpointerException

如何在 JUnit Test Java 中替换 Mockito 以存根类

在 Mockito 中检测到未完成的存根

颤振中的 mockito 缺少存根错误。尝试在模拟的 SharedPreferences 上使用 setString

使用 Mockito 将 Class<T> 作为参数的方法存根

使用 Mockito 多次调用具有相同参数的相同方法