模拟对抽象类的公共方法的调用而不对抽象类进行子类化,最好使用 mockito



我正在使用JUNIT + Mockito编写一个单元测试来测试如下方法:

public someObject methodUnderTest(){
  SomeObject obj = SomeAbstractClass.someMethod();
  if(obj!=null){
    obj.someOtherMethod();
  }
  return someThing;
}

我想模拟上面代码片段中提到的对abstract Class "SomeAbstractClass"调用,以便我可以验证对"obj"的调用,例如:

verify(SomeAbstractClass).someMethod();
verify(obj).someOtherMethod();

我尝试使用模拟功能,例如:Mockito.CALLS_REAL_METHODSMockito.RETURNS_MOCKS

但由于 SomeAbstractClass 不可用的依赖项,它们不起作用。

注意:

1)SomeObject是一个接口。

2)我需要一种技术来测试上面的代码片段。我只能使用上面的代码片段,无法更改代码片段。

您可以使用 PowerMock 来模拟静态方法和最终方法。

听起来问题在于您对CALLS_REAL_METHODS的使用适用于整个类,您真的想模拟特定方法(即进行"部分模拟")。这里有两个选项,一个使用 thenCallRealMethod ,一个使用 CALLS_REAL_METHODS 然后专门模拟您需要的调用:

public void testMethodUnderTest_mockSpecificThings() {
    SomeAbstractClass myAbstractClass = Mockito.mock(SomeAbstractClass.class);
    SomeAbstractClass myObject = Mockito.mock(SomeObject.class);
    when(myAbstractClass.someMethod()).thenReturn(foo);
    when(myAbstractClass.methodUnderTest()).thenCallRealMethod();
    myAbstractClass.methodUnderTest();
    verify(myAbstractClass).someMethod();
    verify(myObject).someOtherMethod();
}
public void testMethodUnderTest_makeSpecificRealCalls() {
    SomeAbstractClass myAbstractClass =
        Mockito.mock(SomeAbstractClass.class, CALLS_REAL_METHODS);
    SomeAbstractClass myObject = Mockito.mock(SomeObject.class);
    // overrides the default answer
    when(myAbstractClass.someMethod()).thenReturn(myObject);
    myAbstractClass.methodUnderTest();
    verify(myAbstractClass).someMethod();
    verify(myObject).someOtherMethod();
}

预先警告 SomeAbstractClass 实际上从未实例化,因此如果您依赖于抽象类构造函数中的任何行为,例如变量初始化(包括声明字段的内联初始化),则需要自己显式进行这些调用。

假设:如果你写单元测试,我想你仍然可以稍微修改测试方法。

溶液:

  1. 将静态方法调用提取到可重写方法:
public someObject methodUnderTest() {
    SomeObject obj = getSomeObject();
    if(obj!=null){
      obj.someOtherMethod();
    }
    return someThing;
}
protected SomeObject getSomeObject() {
    return SomeAbstractClass.someMethod();
}
  1. 然后,您可以使用Mockito Spy来部分模拟您实际测试的对象:
private ClassUnderTest classUnderTest;
@Before
public void setUp() {
    classUnderTest= new ClassUnderTest();
    classUnderTest = Mockito.spy(classUnderTest);
}
@Test
public void test() {
    SomeObject someObject = Mockito.mock(SomeObject.class);
    when(classUnderTest.getSomeObject()).thenReturn(someObject);
    classUnderTest.methodUnderTest();
    verify(someObject).someOtherMethod();
}
@Test
public void testNull() {
    when(classUnderTest.getSomeObject()).thenReturn(null);
    classUnderTest.methodUnderTest();
    verify(something);
}

使用匿名类:

public interface SomeObject {
     public Object someOtherMethod();
}
public abstract class SomeAbstractClass {
    abstract SomeObject someMethod();
}
@Test
public void test() {
    SomeAbstractClass target = new SomeAbstractClass() {
        SomeObject someMethod() {
            // some impl
            SomeObject someObject = new SomeObject() {
                public Object someOtherMethod() {
                    // some other impl
                }
            };
            return someObject;
        }
    };
    // now test target
}

相关内容

  • 没有找到相关文章

最新更新