java 在不继承抽象类的情况下模拟对抽象类的公共方法的调用,最好使用 mockito

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10765273/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 02:27:49  来源:igfitidea点击:

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

javaunit-testingjunitmockingmockito

提问by Mrugen Deshmukh

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.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. I am constrained to use the above code fragment and cannot change the code fragment.

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

采纳答案by volkovs

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:
  1. 将静态方法调用提取到可覆盖的方法:
public someObject methodUnderTest() {
    SomeObject obj = getSomeObject();

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

    return someThing;
}

protected SomeObject getSomeObject() {
    return SomeAbstractClass.someMethod();
}
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:
  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);
}
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);
}

回答by Garrett Hall

You can use PowerMockto mock static and final methods.

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

回答by Jeff Bowman

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 (i.e. make a "partial mock"). You have two options here, one using thenCallRealMethod, and one using CALLS_REAL_METHODSand then specifically mocking the calls you need:

听起来问题在于您对 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();
}

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

回答by Bohemian

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
}