首页 文章

使用mockito测试私有方法

提问于
浏览
75
public class A {

    public void method(boolean b){
          if (b == true)
               method1();
          else
               method2();
    }

    private void method1() {}
    private void method2() {}
}
public class TestA {

    @Test
    public void testMethod() {
      A a = mock(A.class);
      a.method(true);
      //how to test like    verify(a).method1();
    }
}

如何测试私有方法是否被调用,以及如何使用mockito测试私有方法???

10 回答

  • 5

    你不能用Mockito做到这一点,但你可以使用Powermock来扩展Mockito并模拟私有方法 . Powermock支持Mockito . Here就是一个例子 .

  • 15

    不可能通过mockito . 从他们的wiki

    为什么Mockito不会模仿私有方法?首先,我们并不是嘲笑私人方法的教条 . 我们只是不关心私有方法,因为从测试私有方法的角度来看不存在 . 以下是Mockito不会模仿私有方法的几个原因:它需要对类加载器进行黑客攻击,这种类加载器绝不是防弹,它会更改api(必须使用自定义测试运行器,注释类等) . 它很容易解决 - 只需将方法的可见性从私有更改为受包保护(或受保护) . 它需要我花时间实施和维护它 . 鉴于第2点和它已经在不同的工具(powermock)中实现的事实,它没有意义 . 最后...... Mock 私有方法暗示OO理解存在问题 . 在OO中,您希望对象(或角色)进行协作,而不是方法 . 忘记pascal和程序代码 . 在对象中思考 .

  • 4

    这是一个小例子如何用powermock

    public class Hello {
        private Hello obj;
        private Integer method1(Long id) {
            return id + 10;
        }
    }
    

    要测试 method1 使用代码:

    Hello testObj = new Hello();
    Integer result = Whitebox.invokeMethod(testObj, "method1", new Long(10L));
    

    设置私有对象 obj 使用此:

    Hello testObj = new Hello();
    Hello newObject = new Hello();
    Whitebox.setInternalState(testObj, "obj", newObject);
    
  • 20

    从行为的角度考虑这个问题,而不是考虑采用何种方法 . 如果 b 为true,则称为 method 的方法具有特定行为 . 如果 b 为false,则它具有不同的行为 . 这意味着您应该为 method 编写两个不同的测试;每个案例一个 . 因此,不是有三个面向方法的测试(一个用于 method ,一个用于 method1 ,一个用于 method2 ,而是有两个面向行为的测试 .

    与此相关(我最近在另一个SO线程中提出了这个问题,并且结果被称为四个字母的单词,所以请随意拿出一些盐);我发现选择反映我调用你的测试 testMethod()testMethod1()testMethod2() 等行为的测试名称会很有帮助 . 我喜欢像 calculatedPriceIsBasePricePlusTax()taxIsExcludedWhenExcludeIsTrue() 这样的名字来表明我正在测试的行为;然后在每个测试方法中,仅测试指示的行为 . 大多数此类行为仅涉及对公共方法的一次调用,但可能涉及对私有方法的多次调用 .

    希望这可以帮助 .

  • 1

    你不应该测试私有方法 . 只需要测试非私有方法,因为这些方法应该调用私有方法 . 如果您“想”测试私有方法,则可能表明您需要重新考虑您的设计:

    我使用适当的依赖注入吗?我是否可能需要将私有方法移动到单独的类中而是测试它?这些方法必须是私有的吗? ......他们不能默认或受保护吗?

    在上面的例子中,被称为“随机”的两个方法实际上可能需要放在他们自己的类中,测试然后注入上面的类 .

  • 103

    我能够使用反射使用mockito测试一个私有方法 . 这是一个例子,试图将它命名为有意义

    //Service containing the mock method is injected with mockObjects
    
    @InjectMocks
    private ServiceContainingPrivateMethod serviceContainingPrivateMethod;
    
    //Using reflection to change accessibility of the private method
    
    Class<?>[] params = new Class<?>[]{PrivateMethodParameterOne.class, PrivateMethodParameterTwo.class};
        Method m = serviceContainingPrivateMethod .getClass().getDeclaredMethod("privateMethod", params);
        //making private method accessible
        m.setAccessible(true); 
        assertNotNull(m.invoke(serviceContainingPrivateMethod, privateMethodParameterOne, privateMethodParameterTwo).equals(null));
    
  • 1

    我真的不明白你需要测试私有方法 . 根本问题是您的公共方法作为返回类型具有void,因此您无法测试您的公共方法 . 因此,您被迫测试您的私人方法 . 我猜是正确的吗?

    一些可能的解决方案(AFAIK):

    • 嘲笑你的私人方法,但你仍然不会“实际”测试你的方法 .

    • 验证方法中使用的对象的状态 . MOSTLY方法要么对输入值进行一些处理并返回输出,要么改变对象的状态 . 也可以使用测试对象的所需状态 .

    公共课A {

    SomeClass classObj = null;

    public void publicMethod(){
    privateMethod();
    }

    private void privateMethod(){
    classObj = new SomeClass();
    }

    }
    [在这里,您可以通过检查classObj从null到非null的状态更改来测试私有方法 .

    • 稍微重构您的代码(希望这不是遗留代码) . 我编写方法的基础是,应该总是返回一些东西(一个int /一个布尔值) . 实现可以使用或不使用返回值,但测试会使用它

    码 .

    public class A
    { 
        public int method(boolean b)
        {
              int nReturn = 0;
              if (b == true)
                   nReturn = method1();
              else
                   nReturn = method2();
        }
    
        private int method1() {}
    
        private int method2() {}
    
    }
    
  • 2

    将您的测试放在同一个包中,但是使用不同的源文件夹(src / main / java与src / test / java)并将这些方法设置为package-private . Imo可测试性比隐私更重要 .

  • 63

    虽然Mockito不提供该功能,但您可以使用Mockito JUnit ReflectionUtils类或Spring ReflectionTestUtils类来实现相同的结果 . 请参阅以下从here获取的示例,解释如何调用私有方法:

    ReflectionTestUtils.invokeMethod(student, "saveOrUpdate", "From Unit test");
    

    ReflectionTestUtils和Mockito的完整示例可以在书中找到Mockito for Spring

  • 0

    实际上有一种方法可以测试私人会员与Mockito的方法 . 假设你有一个这样的类:

    public class A {
        private SomeOtherClass someOtherClass;
        A() {
            someOtherClass = new SomeOtherClass();
        }
        public void method(boolean b){
            if (b == true)
                someOtherClass.method1();
            else
                someOtherClass.method2();
        }
    
    }
    
    public class SomeOtherClass {
        public void method1() {}
        public void method2() {}
    }
    

    如果你想测试 a.method 将从 SomeOtherClass 调用一个方法,你可以写下面的内容 .

    @Test
    public void testPrivateMemberMethodCalled() {
        A a = new A();
        SomeOtherClass someOtherClass = Mockito.spy(new SomeOtherClass());
        ReflectionTestUtils.setField( a, "someOtherClass", someOtherClass);
        a.method( true );
    
        Mockito.verify( someOtherClass, Mockito.times( 1 ) ).method1();
    }
    

    ReflectionTestUtils.setField(); 会将私人成员与您可以侦察的内容存根 .

相关问题