模拟继承的受保护方法

6

我这里有一个简化版的问题。A类有一个受保护的方法。B类继承了这个方法。

public class A{
    protected String getString(){
        //some Code
    }
}


public class B extends A{
    public void doSomething(){
        //someCode
        String result = getString();
    }
}

我现在使用Mockito编写一个单元测试,该测试位于另一个包的测试中,我想要测试doSomething()方法。为了做到这一点,我需要模拟getString()调用。由于该方法是protected的而我的测试类位于不同的包中,因此我无法使用doReturn(...).when(classUnderTest).getString()。问题在于,我在类B上进行了监视。所以我不能使用mock(new B(), Mockito.CALLS_REAL_METHODS)
我尝试通过反射获取受保护的方法:
Method getString = classUnderTest.getClass().getDeclaredMethod("getString");
getString.setAccessible(true);

但我不知道如何在doReturn()内部使用它。


你为什么要测试不在同一个包中的东西?这可能是你想要纠正的第一件事情。 - Makoto
3个回答

4
您可以使用“覆盖和子类化”来实现。
B b = new B() {
  @Override
  protected String getString() {
    return "FAKE VALUE FOR TESTING PURPOSES";
  };
};

我成功地使用Mockito和Java反射模拟了受保护的方法。答案已添加在此处:https://dev59.com/X5Hea4cB1Zd3GeqPwPVu#69214170 - Debanshu Kundu

2

也许有更简洁的方法,但我们可以这样做:

  1. 创建一个"A"的模拟对象
  2. 创建另一个类继承自"B"并覆盖方法
  3. 在覆盖后的方法中调用模拟对象

例如...

private A partialMock;
private B classUnderTest;

@Before
public void setup() {
    partialMock = mock(A.class);
    classUnderTest = new B() {
        @Override
        protected String getString() {
            return partialMock.getString();
        }
    };
}

@Test
public void shouldDoSomething() {

    when(partialMock.toString()).thenReturn("[THE MOCKED RESPONSE]");

    classUnderTest.doSomething();

    // ...verify stuff...
}

显然,您甚至不需要使用模拟对象,只需直接从重载的方法中返回某些内容即可。

我能够使用Mockito和Java反射来模拟受保护的方法。在此处添加答案:https://dev59.com/X5Hea4cB1Zd3GeqPwPVu#69214170 - Debanshu Kundu

0

对我来说,像以下这样做有效,使用doReturn()和Junit5的ReflectionSupport

[注意:我在Mockito 3.12.4上进行了测试]

var a = spy(new A);
ReflectionSupport.invokeMethod(
        a.getClass().getSuperclass().getDeclaredMethod("getString"),
        doReturn("FAKE VALUE FOR TESTING PURPOSES").when(a));

我认为你的意思是使用new B()而不是new A()来解决所描述的问题。 我怀疑这只适用于A和B在同一个包中的情况。 对于我的问题,A和B位于不同的包中,这种方法行不通(目前)。 - ashley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接