最近,我在用Python开发GUI应用程序时一直在试验TDD。我发现让测试验证我的代码的功能非常令人放心,但遵循TDD的一些推荐做法却很棘手。也就是说,首先编写测试很难。而且我发现很难让我的测试可读(由于大量使用模拟库)。
我选择了一个名为mocker的模拟库。我使用它很多,因为我正在测试的大部分代码调用(a)我的应用程序中依赖于系统状态的其他方法或(b)没有事件循环时不能存在的ObjC / Cocoa对象等。
无论如何,我有很多看起来像这样的测试:
def test_current_window_controller():
def test(config):
ac = AppController()
m = Mocker()
ac.iter_window_controllers = iwc = m.replace(ac.iter_window_controllers)
expect(iwc()).result(iter(config))
with m:
result = ac.current_window_controller()
assert result == (config[0] if config else None)
yield test, []
yield test, [0]
yield test, [1, 0]
请注意,这实际上是三个测试;都使用相同的参数化测试功能。这是正在测试的代码:
def current_window_controller(self):
try:
# iter_window_controllers() iterates in z-order starting
# with the controller of the top-most window
# assumption: the top-most window is the "current" one
wc = self.iter_window_controllers().next()
except StopIteration:
return None
return wc
我使用mocker时注意到的一件事是,首先编写应用程序代码然后再返回并编写第二个测试更容易,因为大部分时间我都在模拟许多方法调用和语法编写模拟调用比应用程序代码更冗长(因此更难编写)。编写应用程序代码然后对其进行建模测试代码会更容易。
我发现使用这种测试方法(以及一些规则),我可以轻松编写100%测试覆盖率的代码。
我想知道这些测试是否是好的测试?当我终于发现编写好测试的秘诀时,我会后悔这样做吗?
我是否违反了TDD的核心原则,以至于我的测试是徒劳的?
答案 0 :(得分:7)
如果您在编写代码并使其通过后编写测试,则表明您没有使用TDD (您也没有获得Test-First或Test-Driven开发的任何好处。查看有关TDD权威书籍的SO问题)
我注意到的一件事 使用mocker是更容易的 首先编写应用程序代码 然后回去写测试 第二,因为大部分时间我都是 模拟许多方法调用和 写入模拟调用的语法是 更加冗长(因此更难) 写)比应用程序代码。它的 然后更容易编写应用程序代码 模拟测试代码。
当然,它更容易,因为你只是通过用特定类型的画笔绘制它来测试天空是橙色的。 这是改造测试(为了自我保证)。模拟很好,但是你应该知道如何以及何时使用它们 - 就像俗话说的那样'当你有一把锤子时,一切看起来像钉子'这也很容易写出一大堆不可读的,而不是有用的。 - 测试。花在理解测试内容上的时间是可以用来修复损坏的时间。
重点是:
答案 1 :(得分:-2)
当您重构代码(即完全重写或移动模块)时,单元测试非常有用。只要您在进行重大更改之前进行单元测试,您就会有信心在完成任务时忘记移动或包含某些内容。
答案 2 :(得分:-3)
请记住TDD不是一个灵丹妙药。这很难,它应该很难,并且“提前”写出模拟测试特别困难。
所以我会说 - 做对你有用的事情。即使它不是“经过认证的TDD”。我基本上做同样的事情。
您可能希望为控制器代码和GUI库代码之间提供自己的GUI API。这可能更容易模拟,或者你甚至可以添加一些测试钩子。
最后但同样重要的是,您的代码对我来说看起来并不太可读。使用模拟的代码通常难以理解。幸运的是,在Python中,模拟比其他语言更容易和更清晰。