【问题标题】:How to mock a single method in java如何在java中模拟单个方法
【发布时间】:2012-06-09 08:53:13
【问题描述】:

是否可以模拟 Java 类的单个方法?

例如:

class A {
    long method1();
    String method2();
    int method3();
}


// in some other class
class B {
    void someMethod(A a) {
       // how would I mock A.method1(...) such that a.method1() returns a value of my
       // choosing;
       // whilst leaving a.method2() and a.method3() untouched.
    }
}

【问题讨论】:

    标签: java mocking


    【解决方案1】:

    使用Mockito'sspy机制:

    A a = new A();
    A aSpy = Mockito.spy(a);
    Mockito.when(aSpy.method1()).thenReturn(5l);
    

    对于任何未存根的方法,使用 spy 调用包装对象的默认行为。

    Mockito.spy()/@Spy

    【讨论】:

    • 或者,如文档所述,in some cases 你需要Mockito.doReturn(51).when(aSpy).method1();
    • 不幸的是,您不能以这种方式监视 final 类的实例。 :(
    • 一般来说,不可能模拟任何最终的东西。 final 类中的方法也被视为 final。
    • @JohnB 我们如何使用Mokito spy 模拟私有方法?
    【解决方案2】:

    使用spy() method from Mockito,并像这样模拟您的方法:

    import static org.mockito.Mockito.*;
    
    ...
    
    A a = spy(new A());
    when(a.method1()).thenReturn(10L);
    

    【讨论】:

      【解决方案3】:

      根据 Mockito 的文档,公认的答案不是窥探真实对象的正确方法。

      正确的做法是使用以下模式:
      doReturn("foo").when(spy).get(0);

      您可以在下面找到来自 Mockito 的关于 Spying on real objects 的 sn-p。

      监视真实物体的重要问题!

      有时这是不可能的或 使用 when(Object) 来存根间谍是不切实际的。因此当 使用间谍请考虑 doReturn|Answer|Throw() 系列方法 用于存根。示例:

      List list = new LinkedList();    
      List spy = spy(list);
      
      //Impossible: real method is called so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)   
      when(spy.get(0)).thenReturn("foo");
      
      //You have to use doReturn() for stubbing   
      doReturn("foo").when(spy).get(0);   
      

      Mockito 委托调用 到传递的真实实例,相反它实际上创建了它的副本。 因此,如果您保留真实实例并与之交互,请不要指望 间谍要意识到这些互动及其对现实的影响 实例状态。推论是当一个 unstubbed 方法是 在间谍上调用不在真实实例上,你不会看到任何 对真实实例的影响。注意最终方法。莫基托 不模拟最终方法,所以底线是:当你监视真实的 对象+您尝试存根最终方法=麻烦。你也不会 也能够验证这些方法。

      【讨论】:

        【解决方案4】:

        假设您使用的是 jmockit:

        public void testCase(@Mocked("methodToBeMocked") final ClassBoBeMocked mockedInstance) {
                   new Expectations() {{
                           mockedInstance.methodToBeMocked(someParameter); returns(whateverYouLikeItToReturn);
                   }}
        
           mockedInstance.callSomemethod();
        }
        

        【讨论】:

          【解决方案5】:

          您可以简单地创建一个覆盖method1()A 的子类。

          【讨论】:

          • 这行不通-因为您必须将 A 的现有实例传递给 A 的子类,以便子类返回 a.method2() 和 a.method3()分别调用 method2() 和 method3()。这意味着子类将覆盖 method2() 和 method3()。
          • @user63904: 啊,所以你想修改方法 1 INSIDE someMethod() 的行为,同时仍然使用作为参数传递的 A 的实例?对,那不行。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-29
          • 1970-01-01
          • 2012-08-04
          • 1970-01-01
          • 1970-01-01
          • 2022-07-06
          相关资源
          最近更新 更多