使用 Mockito 验证函数调用的次数有什么意义?

2022-09-03 01:32:32

在我的理解中,代码测试就是测试结果是否正确,就像计算器一样,我需要写一个测试用例来验证1+1的结果是否为2。

但是我读过很多关于验证方法调用次数的测试用例。我对此感到非常困惑。最好的例子是我刚刚在《春天在行动》中看到的

public class BraveKnight implements Knight {
    private Quest quest;
    public BraveKnight(Quest quest) { 
        this.quest = quest; 
    }
    public void embarkOnQuest() {
        quest.embark(); 
    }
}

public class BraveKnightTest {
    @Test 
    public void knightShouldEmbarkOnQuest() { 
        Quest mockQuest = mock(Quest.class); 
        BraveKnight knight = new BraveKnight(mockQuest); 
        knight.embarkOnQuest(); 
        verify(mockQuest, times(1)).embark(); 
    }
}

我真的不知道为什么他们需要验证函数是否被调用一次。难道你不认为在被调用后肯定会被调用吗?或者会发生一些错误,我会注意到日志中的错误消息,这些消息显示错误行号,可以帮助我快速找到错误的代码。embark()embark()embarkOnQuest()

那么像上面这样验证有什么意义呢?


答案 1

需求很简单:验证是否进行了正确数量的调用。有些情况下,方法调用不应该发生,而有些情况下,方法调用的发生次数应该比默认值多或少。

请考虑以下修改版本:embarkOnQuest

public void embarkOnQuest() {
    quest.embark(); 
    quest.embarkAgain(); 
}

假设您正在测试以下错误案例:quest.embark()

@Test 
public void knightShouldEmbarkOnQuest() { 
    Quest mockQuest = mock(Quest.class); 
    Mockito.doThrow(RuntimeException.class).when(mockQuest).embark();
    ...
}

在这种情况下,您需要确保 未被调用(或被调用 0 次):quest.embarkAgain

verify(mockQuest, times(0)).embarkAgain(); //or verifyZeroInteractions

当然,这是另一个简单的例子。还可以添加许多其他示例:

  • 一个数据库连接器,应该在第一次读取时缓存条目,可以进行多次调用并验证与数据库的连接是否只被调用一次(每个测试查询)
  • 在加载时(或懒惰地)执行初始化的单例对象,可以测试与初始化相关的调用是否只进行一次。

答案 2

请考虑以下代码:

public void saveFooIfFlagTrue(Foo foo, boolean flag) {
    if (flag) {
        fooRepository.save(foo);
    }
}

如果您不检查 调用的次数 ,那么您如何知道此方法是否正在执行您希望它执行的操作?fooRepository.save()

这适用于其他 void 方法。如果没有返回某个方法,因此没有要验证的响应,则检查调用了哪些其他方法是验证该方法行为是否正确的好方法。


推荐