2 回答
TA贡献1790条经验 获得超9个赞
TDD 中通常的答案是您将函数分为两部分;一个易于测试的部分,但与特定文件句柄或 os::Exit 的特定实现不紧密耦合;另一部分与这些东西是紧密耦合的,但是如此简单,显然没有任何不足之处。
您的“单元测试”是测量第一部分的错误检测器。
第二部分你写一次,“用手”检查它,然后不管它。这里的想法是事情是如此简单,一旦正确实施,它们就不需要改变。
// Warning: untested code ahead
func Foo_is_very_stable() {
bar_is_easy_to_test(stdin, stdout, os.exit)
}
func bar_is_easy_to_test(in *File, out *File , exit func(int)) {
// Do complicated things here.
}
现在,我们有点作弊——os.exit这是一种永远不会回来的特殊魔法,但bar_is_easy_to_test并不真正知道这一点。
另一种更公平一点的设计是将复杂的代码放入状态机中。状态机决定做什么,调用机器的主机决定如何做……
// More untested code
switch state_machine.next() {
case OUT:
println(state_machine.line())
state_machine.onOut()
case EXIT:
os.exit(state_machine.exitCode())
同样,您会得到一个易于测试的复杂部分(状态机)和一个更简单的稳定且易于通过检查验证的部分。
这是 TDD 的核心思想之一——我们故意以“易于测试”的方式设计我们的代码。这样做的理由是声称易于测试的代码也易于维护(因为很容易检测到错误并且因为设计本身“更干净”)。
TA贡献1786条经验 获得超11个赞
你所拥有的东西被称为“副作用” - 当你的应用程序的执行跨越它的环境时,它是地址空间的情况。问题是,你不测试副作用。这并不总是可能的,而且当它是 - 它是不合理的复杂和丑陋的。
基本思想是让你的副作用,如 CLI 输出或os.Exit()(或网络连接,或访问文件),与你的逻辑主体分离。有很多方法可以做到这一点,整个“软件设计”学科都致力于此,@VoiceOfUnreason 给出了几个可行的例子。
在您的示例中,我将在函数中包装副作用并安排某种方式将依赖项注入Success()& Error()。如果您想保留这两个简单的函数,那么它要么是函数参数,要么是持有退出函数的全局变量(根据@Peter 的评论),但我建议采用 OO 方式,采用一些 模式并实现更大为您提供灵活性。
- 2 回答
- 0 关注
- 229 浏览
添加回答
举报
