不使用像MockK或Mockito这样的测试框架似乎变得越来越流行了。我决定尝试这种方法。到目前为止,返回假数据很简单。但是我如何验证一个函数(不返回数据)已经被调用了呢?想象一下有一个这样的类:
class TestToaster: Toaster {
override fun showSuccessMessage(message: String) {
throw UnsupportedOperationException()
}
override fun showSuccessMessage(message: Int) {
throw UnsupportedOperationException()
}
override fun showErrorMessage(message: String) {
throw UnsupportedOperationException()
}
override fun showErrorMessage(message: Int) {
throw UnsupportedOperationException()
}
}
有了MockK我会做
verify { toaster.showSuccessMessage() }
我不想重新发明一个轮子,所以决定问。在谷歌上找到任何东西似乎是非常困难的。既然这是一件事,我认为重点将是完全删除嘲笑库,没有它们一切都可以做。
2条答案
按热度按时间zqdjd7g91#
在模拟库出现之前,传统的做法是手动创建一个测试实现。测试实现将存储一个方法是如何被调用到某个内部状态的,这样测试代码就可以通过检查相关状态来验证一个方法是否是用预期的参数调用的。
例如,一个非常简单的Toaster测试实现可以是:
然后在测试代码中,配置要测试的对象使用
MockToaster
。为了验证它是否真的调用了showSuccessMessage("foo")
,可以在测试结束时Assert它的showSuccesMessageStr
是否等于foo
。rsl1atfo2#
很多人似乎都在建议非常直接的解决方案,这完全有道理。我决定用一点花哨的语法来实现这个语法:
verify(toaster = toaster, times = 1).showErrorMessage(any<String>())
.我创建了简单的匹配器:
添加了一个Map来存储TestToaster中每个方法的调用计数,其中key是函数的名称,value是计数:
private var callCount: MutableMap<String, Int> = mutableMapOf()
个每当一个函数被调用时,我增加一个方法的当前调用计数值。我通过反射得到当前方法名
为了实现“花哨”的语法,我为
TestToaster
创建了内部子类和一个verify
函数:该函数将当前的
toaster
示例发送到内部子类以创建新示例并返回它。当我用上面的语法调用子类的方法时,会进行检查。如果检查通过,则什么也不发生,测试也通过;如果条件不满足,则抛出异常。为了使它更通用和可扩展,我创建了这个接口:
下面是完整的类:
我还没有广泛地测试它,它会随着时间的推移而发展,但到目前为止,它对我来说工作得很好。
我还在Medium上写了一篇关于这方面的文章:https://sermilion.medium.com/unit-testing-verify-that-a-method-was-called-without-testing-frameworks-like-mockito-or-mockk-433ef8e1aff4