最近,我在用Python开发GUI应用程序时一直在尝试TDD。我感到非常放心的是,有一些测试可以验证我的代码的功能,但是遵循一些推荐的TDD做法是很棘手的。即,首先编写测试非常困难。而且我发现很难使我的测试更具可读性(由于广泛使用了模拟库)。
我选择了一个名为mocker的模拟库。我经常使用它,因为我正在测试的许多代码都调用了(a)我的应用程序中依赖于系统状态的其他方法,或者(b)没有事件循环就无法存在的ObjC / Cocoa对象。<铅>
无论如何,我有很多看起来像这样的测试:
1 2 3 4 5 6 7 8 9 10 11 12
| 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] |
请注意,这实际上是三个测试;都使用相同的参数化测试功能。这是正在测试的代码:
1 2 3 4 5 6 7 8 9
| 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 |
我注意到使用模拟程序的一件事是,首先编写应用程序代码然后再返回然后编写测试更加容易,因为大多数时候我都在模拟许多方法调用和编写模拟调用的语法比应用程序代码更为冗长(因此更难编写)。编写应用程序代码然后从中建模测试代码更加容易。
我发现使用这种测试方法(需要一点纪律),我可以轻松地编写覆盖率达到100%的代码。
我想知道这些测试是否很好?当我终于发现编写好的测试的秘诀时,我会后悔这样做吗?
我是否违反了TDD的核心原则,以至于我的测试徒劳无功?
如果您在编写代码并通过测试之后再编写测试,则说明您没有在进行TDD(也没有获得"测试优先"或"测试驱动"开发的任何好处。关于TDD的权威书籍)
One of the things I've noticed with
using mocker is that it's easier to
write the application code first and
then go back and write the tests
second, since most of the time I'm
mocking many method calls and the
syntax to write the mocked calls is
much more verbose (thus harder to
write) than the application code. It's
easier to write the app code and then
model the test code off of that.
当然,它更容易,因为您只是通过使用特定类型的笔刷将天空变成橙色后才测试天空是否为橙色。
这是翻新测试(用于自保)。模仿是好的,但您应该知道如何以及何时使用它们-俗话说"'当您有榔头时,一切看起来都像钉子''也很容易写出一大堆难以理解且不那么容易理解的内容。可能有用的测试。花费在理解测试内容上的时间是可以用来修复损坏的测试的时间。
关键是:
-
Read Mocks不是Stubbing-Martin Fowler(如果您还没有的话)。 Google列出了一些记录良好的ModelViewPresenter模式GUI的实例(如果需要,可以伪造/模拟UI)。
-
研究您的选择并明智地选择。我会用白色光环打在你左肩上的家伙,说"不要做。"。阅读有关我的原因的问题-圣贾斯汀在你的右肩上。我相信他还有话要说:)
在重构代码(即完全重写或移动模块)时,单元测试非常有用。只要在进行大的更改之前先进行单元测试,就可以确信自己在完成操作后不会忘记移动或包含某些内容。
请记住,TDD不是万能药。很难,应该很难,而且"提前"编写模拟测试尤其困难。
所以我想说-做对您有用的事。即使它不是"认证的TDD"。我基本上做同样的事情。
您可能希望提供自己的GUI API,该API位于控制器代码和GUI库代码之间。这可能更容易模拟,或者甚至可以向其中添加一些测试钩子。
最后但并非最不重要的一点是,您的代码对我来说似乎不太可读。使用模拟的代码通常更难理解。幸运的是,在Python中,模拟比其他任何一种语言都更加轻松和简洁。