简体   繁体   English

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

[英]Mocking a call on a public method of an abstract class without subclassing the abstract Class, using mockito prefererably

I am writing an unit testing using JUNIT + Mockito to test a method like : 我正在编写一个使用JUNIT + Mockito测试方法的单元测试:

public someObject methodUnderTest(){
  SomeObject obj = SomeAbstractClass.someMethod();

  if(obj!=null){
    obj.someOtherMethod();
  }

  return someThing;
}

And I would like to mock the call on abstract Class "SomeAbstractClass" mentioned in above code fragment so i can verify call on "obj" like : 我想在上面的代码片段中提到的abstract Class "SomeAbstractClass"上模拟调用,这样我就可以验证对“obj”的调用,如:

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

I have tried using mockito features like : Mockito.CALLS_REAL_METHODS Mockito.RETURNS_MOCKS 我尝试过使用mockito功能,例如:Mockito.CALLS_REAL_METHODS Mockito.RETURNS_MOCKS

but they don't work due to dependencies not available to the SomeAbstractClass. 但由于SomeAbstractClass不可用的依赖项,它们不起作用。

Note: 注意:

1) SomeObject is an Interface. 1)SomeObject是一个接口。

2) I need a technique to test above code fragment. 2)我需要一种技术来测试上面的代码片段。 I am constrained to use the above code fragment and cannot change the code fragment. 我被限制使用上面的代码片段,不能更改代码片段。

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

It sounds like the problem is that your use of CALLS_REAL_METHODS is applying to the entire class, where you really want to mock out specific methods (ie make a "partial mock"). 听起来问题是您对CALLS_REAL_METHODS的使用正在应用于整个类,您真正想要模拟特定方法(即进行“部分模拟”)。 You have two options here, one using thenCallRealMethod , and one using CALLS_REAL_METHODS and then specifically mocking the calls you need: 这里有两个选项,一个使用thenCallRealMethod ,一个使用CALLS_REAL_METHODS ,然后专门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();
}

Be forewarned that SomeAbstractClass is never actually instantiated, so if you rely on any behavior in the abstract class constructor, like variable initialization--including inline initialization where the fields are declared--you will need to make those calls explicitly yourself. 预先警告SomeAbstractClass从未实际实例化,因此如果您依赖于抽象类构造函数中的任何行为,如变量初始化 - 包括声明字段的内联初始化 - 您将需要自己明确地进行这些调用。

Use anonymous classes: 使用匿名类:

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
}

Assumption: if you write unit test, I guess you still can modify tested method a bit. 假设:如果你编写单元测试,我猜你还是可以修改一下测试方法。

Solution: 解:

  1. extract static method call to overridable method: 提取静态方法调用可覆盖的方法:
 public someObject methodUnderTest() { SomeObject obj = getSomeObject(); if(obj!=null){ obj.someOtherMethod(); } return someThing; } protected SomeObject getSomeObject() { return SomeAbstractClass.someMethod(); } 
  1. then you can use Mockito Spy to partially mock the object you actually test: 那么你可以使用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); } 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM