使用 Mockito 测试抽象类

我想测试一个抽象类。当然,我可以手动编写一个从该类继承的模拟。

我可以使用模拟框架(我使用的是Mockito)而不是手工制作我的模拟来做到这一点吗?如何?


答案 1

下面的建议让你测试抽象类而不创建一个“真实”的子类 - Mock子类。

使用 ,然后模拟调用的任何抽象方法。Mockito.mock(My.class, Mockito.CALLS_REAL_METHODS)

例:

public abstract class My {
  public Result methodUnderTest() { ... }
  protected abstract void methodIDontCareAbout();
}

public class MyTest {
    @Test
    public void shouldFailOnNullIdentifiers() {
        My my = Mockito.mock(My.class, Mockito.CALLS_REAL_METHODS);
        Assert.assertSomething(my.methodUnderTest());
    }
}

注意:此解决方案的美妙之处在于,您不必实现抽象方法,只要从不调用它们即可。

老实说,这比使用间谍更整洁,因为间谍需要一个实例,这意味着你必须创建抽象类的可实例化子类。


答案 2

如果你只需要测试一些具体的方法而不触及任何抽象,你可以使用(参见Morten的答案),但是如果被测试的具体方法调用一些抽象,或者未实现的接口方法,这将不起作用 - Mockito会抱怨“无法在java接口上调用real method”。CALLS_REAL_METHODS

(是的,这是一个糟糕的设计,但有些框架,例如Tapestry 4,有点强迫你。

解决方法是反转这种方法 - 使用普通的模拟行为(即,所有内容都被模拟/存根),并用于显式调用所测试的具体方法。例如:doCallRealMethod()

public abstract class MyClass {
    @SomeDependencyInjectionOrSomething
    public abstract MyDependency getDependency();

    public void myMethod() {
        MyDependency dep = getDependency();
        dep.doSomething();
    }
}

public class MyClassTest {
    @Test
    public void myMethodDoesSomethingWithDependency() {
        MyDependency theDependency = mock(MyDependency.class);

        MyClass myInstance = mock(MyClass.class);

        // can't do this with CALLS_REAL_METHODS
        when(myInstance.getDependency()).thenReturn(theDependency);

        doCallRealMethod().when(myInstance).myMethod();
        myInstance.myMethod();

        verify(theDependency, times(1)).doSomething();
    }
}

更新以添加:

对于非 void 方法,您需要使用 thenCallRealMethod() 代替,例如:

when(myInstance.myNonVoidMethod(someArgument)).thenCallRealMethod();

否则,Mockito会抱怨“检测到未完成的存根”。


推荐