【问题标题】:How to mock protected subclass method inherited from abstract class?如何模拟从抽象类继承的受保护的子类方法?
【发布时间】:2015-08-18 12:58:21
【问题描述】:

如何使用 Mockito 或 PowerMock 模拟由子类实现但继承自抽象超类的受保护方法?

换句话说,我想在模拟“doSomethingElse”的同时测试“doSomething”方法。

抽象超类

public abstract class TypeA {

    public void doSomething() {     

        // Calls for subclass behavior
        doSomethingElse();      
    }

    protected abstract String doSomethingElse();

}

子类实现

public class TypeB extends TypeA {

    @Override
    protected String doSomethingElse() {
        return "this method needs to be mocked";
    }

}

解决方案

这里给出的答案是正确的,如果所涉及的类在同一个包中,则将起作用。

但如果涉及不同的软件包,一种选择是使用 PowerMock。以下示例对我有用。当然,可能还有其他方法可以做到这一点,这是可行的。

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ TypeB.class })
public class TestAbstract {

    @Test
    public void test_UsingPowerMock() throws Exception {
        // Spy a subclass using PowerMock
        TypeB b = PowerMockito.spy(new TypeB());
        String expected = "some value for mock";

        // Mock a method by its name using PowerMock again
        PowerMockito.doReturn(expected).when(b, "doSomethingElse");

        // Calls the 
        String actual = b.doSomething();
        assertEquals(expected, actual);     

    }
}

注意:使用 Java 5、jUnit 4.11、Mockito 1.9.0 和 PowerMock 1.4.12 完成的测试。

【问题讨论】:

  • 这种方法给了我一个NullPointerException 与 Java 8、JUnit 4.12 和 PowerMock 1.6.4。
  • @Mack 你解决了吗?
  • @ceyun 我很抱歉,但我不记得我是否解决了它,或者如果我解决了,如何解决。也许是其中一个支持我的评论的人记得?

标签: java unit-testing junit mockito powermock


【解决方案1】:

模拟抽象方法时可以使用Mockito.CALLS_REAL_METHODS。这将调用该类的原始方法,您可以自己模拟所有抽象方法。

TypeA typeA = mock(TypeA.class, Mockito.CALLS_REAL_METHODS);
when(typeA.doSomethingElse()).thenReturn("Hello");
typeA.doSomething();

或者你直接用间谍在 TypeB 上测试:

TypeB typeB = spy(new TypeB());
when(typeB.doSomethingElse()).thenReturn("Hello");
typeB.doSomething();

【讨论】:

  • 第一个选项失败,因为 TypeA 是抽象的。选项 2 适用于 spy(),但是当我尝试将其应用到我的生产代码中时,它给了我 The method <method name> from the type <subclass name> is not visible。试图找出原因。
  • 实际上你的测试是正确的,但是我有不同包中的类,这就是为什么我不能更早地做到这一点。受保护的方法在其他包中不可见。
  • 第一个选项也有效吗?我已经使用 Mockito 1.10.19 和最新的 beta 版本进行了测试,并且都按预期工作。
  • 确实有效。忘了告诉你我的 Mockito 版本很古老,1.9.0,因为 Java 5。
【解决方案2】:

我建议为此使用 Mockito:

// Create a new Mock
final TypeA a = Mockito.mock(TypeA.class, Mockito.CALLS_REAL_METHODS);

// Call the method
a.doSomething();

// Now verify that our mocked class' method was called
Mockito.verify(a, Mockito.times(1)).doSomethingElse();

【讨论】:

  • 它有效,但我刚刚意识到我的生产代码中有不同包中的类。受保护的方法此时不可见。
  • 这使它成为一个问题。一个可能的解决方案是使用 PowerMock,它应该能够验证私有方法,afaik。不过没用过。
【解决方案3】:

您可以通过以下方式使用 mockito 测试您的抽象类

TypeA typA = Mockito.mock(TypeA.class, Mockito.CALLS_REAL_METHODS);
when(typA.doSomethingElse()).thenReturn("doSomethingElse");
Assert.assertSomething(typeA.doSomething());

【讨论】:

    【解决方案4】:

    要模拟在抽象类中返回 void 的方法,我们可以使用:

    MyAbstractClass abs = Mockito.mock(MyAbstractClass.class);
    Mockito.doNothing().when(abs).myMethod(arg1,arg2....));
    

    我们可以根据要求将参数替换为 Mockito.anyString() 等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-17
      • 1970-01-01
      • 2011-09-18
      • 2017-11-28
      • 1970-01-01
      • 1970-01-01
      • 2019-12-09
      相关资源
      最近更新 更多