【问题标题】:How to mock a call of an inner method from a Junit如何模拟从 Junit 调用内部方法
【发布时间】:2020-05-28 03:14:03
【问题描述】:

我有 MyClass,我正在为每个方法做一个测试类 (Method1Test)

public class MyClass {
    public int method1(){
        int a = method2();
        return a;
    }
    public int method2(){
        return 0;
    }
}

@RunWith(MockitoJUnitRunner.class)
public class Method1Test {
    @InjectMocks
    private MyClass myClass = new MyClass();
    @Before
    public void setup(){}
    @Test
    public void test01(){
        Mockito.when(myClass.method2()).thenReturn(25);
        int a = myClass.method1();
        assertTrue("We did it!!!",a==25);
    }
}

问题是我无法模拟对 method2 的调用以使其返回不同的值。 Mockito 语句不起作用。

非常感谢^_^

【问题讨论】:

    标签: java junit mocking mockito


    【解决方案1】:

    您必须在被测类上创建一个间谍并通过重新定义该间谍的method2() 的行为来部分模拟它

    import static org.junit.Assert.assertEquals;
    import static org.mockito.Mockito.spy;
    import static org.mockito.Mockito.when;
    
    
    public class Method1Test {
    
      private MyClass myClass = new MyClass();
    
      @Test
      public void test01(){
        //given
        MyClass spy = spy(myClass); //create a spy for class-under-test
        when(spy.method2()).thenReturn(25); //partially override behavior of the spy
        //when
        int a = spy.method1(); //make the call to method1 of the _spy_!
        //then
        assertEquals(25, a);
      }
    }
    

    除此之外,您的测试不需要 Mockito Runner 和 @InjectMocks,因为您没有将 @Mock 带注释的模拟注入到被测类中。

    此外,assertTrue 语句中的消息仅在断言条件满足时才会显示。所以应该是至少“我们失败了!!!” ;)

    【讨论】:

      【解决方案2】:

      最后我找到了一个没有创建新类的横向解决方案(我一直无法做到,因为它在实际项目中是被禁止的)。我已经覆盖了测试中的方法。

      解决办法是

      public class MyClass {
          public int method1(){
              int a=0;
              a=method2();
              return a;
          }
          public int method2(){
              return 1;
          }
      }
      
      @RunWith(MockitoJUnitRunner.class)
      public class Method1Test {
          @InjectMocks
          private MyClass myClass = new MyClass(){
              public int method2(){
                  return 25;
              }
          };
          @Before
          public void setup(){}
          @Test
          public void test001(){
              Mockito.when(myClass.method2()).thenReturn(25);
              int a = myClass.method1();
              assertTrue("We did it!!!",a==25);
          }
      }
      

      【讨论】:

      • 从技术上讲,您正在创建一个新类,尽管它是一个匿名类。但是你现在所做的就像在前模拟时代所做的那样,自己编写模拟。改用间谍。
      • 所以,在我看来,我不同意您的解决方案,因为您只覆盖了测试中的方法。你能想象测试不同的方法并覆盖每一个吗?很尴尬。
      【解决方案3】:

      我使用下面的代码尝试了解决方案,但没有通过。

      Mockito.when(myClass.method2()).thenReturn(25);
      

      之后,我尝试了不同的代码,而不是上面的sn-p,测试成功了。看看:

      Mockito.doReturn(25).when(myClass).method2();
      

      为了模拟一个测试(它可能是一个内部方法),你必须使用 doReturn() 方法。

      对于任何方法,您都可以使用 doThrow()、doAnswer()、doNothing()、doReturn() 和 doCallRealMethod() 来代替使用 when() 的相应调用。当你有必要时

      • 存根无效方法
      • 间谍对象的存根方法(见下文)
      • 多次存根同一方法,以在测试过程中更改模拟的行为。

      但您可能更喜欢使用这些方法来代替替代方法 使用 when(),用于所有的存根调用。

      更多信息可以在这里阅读https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#12

      【讨论】:

        【解决方案4】:

        我们需要使用 Mockito.spy() 来模拟我们正在测试的同一个类,而不是在这里使用 mock(class)。然后我们就可以mock我们想要的方法如下。

        @Test
        
          public void method1Test() { 
        
          MyClass myClass = new MyClass();
        
          MyClass myClass1 = Mockito.spy(myClass);
        
          Mockito.doReturn(1).when(myClass1).method2();
        
          Assert.assertEquals(1, myClass1.method1());
        
             }
         }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-12-18
          • 2011-02-15
          • 1970-01-01
          相关资源
          最近更新 更多