Mockito - 验证一个方法是否调用了同一类中的另一个方法

4

我将尝试测试一个方法是否在同一类中调用另一个方法。例如:

public class Foo {

    public void bar(String a){
        switch(a) {
            case "callBaz":
                baz(a);
                break;
            case "callBat":
                bat(a);
                break;
            default:
                System.out.println("Input was " + a);
        }
    } 

    public void baz(String b){
        System.out.println(b);
    }

    public void bat(String c){
        System.out.println(c);
    }
}

然而,如果我尝试在类本身上使用Mockito进行验证:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
public class FooTest {
    @Test
    public void testBazCalledFromBar(){
        Foo foo = new Foo();
        foo.bar("callBaz");
        Mockito.verify(foo).baz("callBaz");
    }
}

我遇到了异常:

org.mockito.exceptions.misusing.NotAMockException: 
Argument passed to verify() is of type Foo and is not a mock!
Make sure you place the parenthesis correctly!
See the examples of correct verifications:
    verify(mock).someMethod();
    verify(mock, times(10)).someMethod();
    verify(mock, atLeastOnce()).someMethod();

使用mock时: ...
@RunWith(SpringJUnit4ClassRunner.class)
public class FooTest {
    @Test
    public void testBazCalledFromBar(){
        Foo fooMock = Mockito.mock(Foo.class);
        fooMock.bar("callBaz");

        Mockito.verify(fooMock).baz("callBaz");
    }
}

I get the exception:

Wanted but not invoked:
foo.baz("callBaz");
-> at com.mn.stagportal.view.employee.FooTest.testBazCalledFromBar(FooTest.java:15)
However, there were other interactions with this mock:
foo.bar("callBaz");
-> at com.mn.stagportal.view.employee.FooTest.testBazCalledFromBar(FooTest.java:13)

有人知道如何测试 baz("callBaz") 是否被调用了吗?


这似乎是一个奇怪的测试需求。你应该测试bar产生的正确效果,而不是它使用哪些辅助方法来实现该效果。你的单元测试不应依赖于方法的特定实现——这不是正确的测试方式。 - Dawood ibn Kareem
@DawoodibnKareem:我知道这不是首选的单元测试方式,但由于有许多条件语句,我想独立测试主方法而不涉及子方法。并且分别测试子方法。我想我可能需要重新开始。 - Lao
2个回答

7
这应该可以正常工作。
@RunWith(SpringJUnit4ClassRunner.class)
public class FooTest {
  @Test
  public void testBazCalledFromBar(){
    Foo fooMock = Mockito.mock(Foo.class);
    doCallRealMethod().when(fooMock).bar(anyString());
    fooMock.bar("callBaz");

    Mockito.verify(fooMock).baz("callBaz");
  }
}

问题是,由于fooMock是一个模拟对象,当它遇到这行代码时: fooMock.bar("callBaz"); 它不知道该怎么办。您需要告诉Mockito,您是想模拟方法调用还是要调用真实的方法。
只有当代码流程到达该实际方法并调用baz方法时,Verify才能起作用。

这非常有帮助,谢谢! - Apoorv Bedmutha

4

不应该嘲笑被测试的对象,可以使用spy代替:

@RunWith(SpringJUnit4ClassRunner.class)
public class FooTest {
  @Test
  public void testBazCalledFromBar(){
    Foo foo = Mockito.spy(Foo.class);
    foo.bar("callBaz");
    Mockito.verify(foo).baz("callBaz");
  }
}

或者

@RunWith(SpringJUnit4ClassRunner.class)
public class FooTest {
  @Test
  public void testBazCalledFromBar(){
    Foo foo = Mockito.spy(new Foo(/* params */));
    foo.bar("callBaz");
    Mockito.verify(foo).baz("callBaz");
  }
}

这似乎无法使用非0参数构造函数工作。我遇到了一个MockitoException: Caused by: org.mockito.internal.creation.instance.InstantationException: 无法创建'Foo$$EnhancerByMockitoWithCGLIB$$fdafa2c2'的实例。 请确保它具有调用干净的0参数构造函数。我会更新我的问题以更好地反映问题。 - Lao
@Lao 当然,Mockito.spy() 可以接收一个类来实例化,或者一个已经实例化的对象。 - Klaimmore

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接