【问题标题】:Mocking of a constructor which gives the base class reference using Powermockito in java在 java 中使用 Powermockito 提供基类引用的构造函数的模拟
【发布时间】:2016-12-15 17:07:46
【问题描述】:

这是场景,我的一个类 MyClass

的方法中有类似的东西
public class MyClass{

    public Object build(Map map) {

        BaseClass cls;     

        if(SomeconditionTrue) {

         cls = new ChildClass1(new ABC());

        } else {

        cls = new ChildClass2(new ABC());

       }

       cls.callMethod();

    }

}

对于上述场景,我正在使用 PowerMockito 编写一个测试用例,我想模拟这个方法调用,cls.callMethod()。当我试图模拟时,它调用实际的方法callMethod() 失败。有人可以帮我模拟那个方法调用吗?尝试使用 PowerMockito PowerMockito.stub 和其他一些选项使用几个场景,但它总是调用实际方法。 mock这个方法的原因是,它的逻辑不同,调用的API也不同,方法比较复杂,所以我们需要mock这个方法。

【问题讨论】:

    标签: java unit-testing mockito powermockito


    【解决方案1】:

    您可以为此求助于 Powermock,但这不一定是此类问题的“最佳”答案。

    本质上,您在代码中调用 new 的事实让您感到悲痛——您由此创建了难以测试的代码。您可以观看这些videos 以了解我在说什么。

    长话短说:与其求助于大的 Powermock 锤子,您可以改写代码;使用依赖注入。因此,您的测试类可以使用一些工厂对象来提供它需要的对象,而不是自己创建这些对象。然后您可以使用任何“普通”模拟框架(例如 EasyMock 或 Mockito)来创建该工厂的模拟版本。

    编辑:我认为您可能使整个问题过于复杂。你看,有一个基类或两个子类并不重要。问题是:对于您的每种测试方法,您应该准确了解将采用哪条路径。您要么想要创建一个 child1,要么是一个孩子。因此,我为您创建了一个简化的解决方案:

    package ghostcat.test;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.Mockito;
    import org.powermock.api.mockito.PowerMockito;
    import org.powermock.core.classloader.annotations.PrepareForTest;
    import org.powermock.modules.junit4.PowerMockRunner;
    
    class Abc {}
    
    abstract class Base {
      void callMethod() {
        System.out.println("Base::callMethod");
      }
    }
    
    class ChildClass1 extends Base {
      ChildClass1(Abc abc) {}
    }
    
    class MyClass {
      public Object build() {
        System.out.println("build1");
        Base cls = new ChildClass1(new Abc());
        System.out.println("build2");
        cls.callMethod();
        System.out.println("build3");
        return null;
      } 
    }
    
    @RunWith(PowerMockRunner.class)
    @PrepareForTest(MyClass.class)
    public class MockNewTest {
      @Test
      public void test() throws Exception {
        ChildClass1 mock = Mockito.mock(ChildClass1.class);
    PowerMockito.whenNew(ChildClass1.class).withArguments(Mockito.any(Abc.class)).thenReturn(mock);
        new MyClass().build();
    }
    

    }

    打印:

    build1
    build2
    build3
    

    所以你可以看到 - 没有调用 base ;仅仅因为那个子对象被“完全”模拟了。

    重点是:您的被测代码只需要一个特定类型的对象;你提前知道那是child1还是child2。因此,您只需为该类创建一个 mock;并使用 PowerMockito 来返回您刚刚创建的 模拟。

    郑重声明:我和间谍玩了一段时间;但他们在这里没有帮助;而且它们也不是必需的!

    【讨论】:

    • 感谢您的回复。是的,我们可以采用一些工厂模式,但我正在编写的测试用例是针对遗留代码的,我们不想触及现有代码。除了更改现有代码之外,还有其他选择吗?
    • @user2334926 我更新了我的答案;引入了一个对我有用的完整示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-28
    • 2016-09-23
    相关资源
    最近更新 更多