在没有子类化抽象类的情况下模拟对抽象类的公共方法的调用,优先使用mockito

时间:2012-05-26 10:00:57

标签: java unit-testing junit mocking 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功能: Mockito.CALLS_REAL_METHODS Mockito.RETURNS_MOCKS

但由于SomeAbstractClass无法使用的依赖项,它们无法正常工作。

注意:

1)SomeObject是一个接口。

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

4 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

听起来问题是您对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实际上从未实例化,因此如果您依赖抽象类构造函数中的任何行为,例如变量初始化 - 包括声明字段的内联初始化 - 您将需要自己明确地进行这些调用。

答案 2 :(得分:1)

使用匿名类:

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
}

答案 3 :(得分:1)

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

解决方案:

  1. 提取静态方法调用overoverable方法:
  2. public someObject methodUnderTest() {
        SomeObject obj = getSomeObject();
    
        if(obj!=null){
          obj.someOtherMethod();
        }
    
        return someThing;
    }
    
    protected SomeObject getSomeObject() {
        return SomeAbstractClass.someMethod();
    }
    
    1. 然后您可以使用Mockito Spy来部分模拟您实际测试的对象:
    2. 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);
      }