测试GUI代码:我应该使用模拟库吗?
最近,我一直在用Python开发一个GUI应用程序的同时尝试使用TDD。我发现验证我的代码功能的测试非常令人放心,但遵循TDD的一些推荐做法非常棘手。也就是说,首先写测试很困难。我发现很难让我的测试可读(由于大量使用模拟库)。测试GUI代码:我应该使用模拟库吗?
我选择了一个名为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
一个我用嘲笑者注意到的事情是,它更容易第二首写的应用程序代码,然后回去写测试,因为大多数的我嘲笑了许多方法调用,编写模拟调用的语法比应用程序代码更冗长(因此写得更难)。编写应用程序代码更容易,然后将测试代码模型化。
我发现使用这种测试方法(以及一些学科),我可以轻松编写100%测试覆盖率的代码。
我想知道这些测试是否是好的测试?当我终于发现编写好的测试的秘密时,我会后悔这样做吗?
我是否违反了TDD的核心原则,以至于我的测试徒劳无功?
单元测试在重构代码时非常有用(即完全重写或移动模块)。只要你在进行大的改变之前进行单元测试,你就会有信心在你完成时没有忘记移动或包含某些东西。
如果您在编写代码并使其通过之后编写测试,那么您没有执行TDD(您也没有从Test-First或Test-Driven开发中获得任何好处..请查看SO对TDD权威书籍)
的事情之一,问题我已经与 用嘲弄的是,它更容易 先写的应用程序代码和 然后回去写测试 第二,因为大多数注意到我是 嘲笑许多方法调用和 s yntax编写的模拟调用比应用程序代码更加详细(因此难以写入 ) 。这是 更容易编写应用程序代码,然后 模拟测试代码。
当然,它更容易,因为你只是在用特定类型的笔刷绘制橙色后测试天空是橙色的。 这是加装测试(用于自我保证)。嘲笑是好的,但你应该知道如何以及何时使用它们 - 正如俗话所说'当你有一把锤子时,一切看起来都像钉子一样'编写一整本不可读的,不太可能的帮助文档也很容易 - 测试。花费时间了解测试的内容是可以用来修复损坏的时间。
而且一点是:
- 阅读Mocks aren't stubs - Martin Fowler如果您还没有。谷歌出了一些记录良好ModelViewPresenter图案化的图形用户界面(假的/模拟出的UI如果需要的)实例。
- 研究你的选择,并明智地选择。我会用白色的左肩上的光环扮演那个说'不要这样做'的人。阅读这个问题关于my reasons - 圣贾斯汀在你的右肩上。我相信他也有话要说:)
请记住,TDD不是一个万能的。这很难,它应该很难,“提前”写嘲笑测试特别困难。
所以我会说 - 做什么适合你。即使它不是“认证的TDD”。我基本上做同样的事情。
您可能希望为GUI提供您自己的API,该API位于控制器代码和GUI库代码之间。这可能更容易模拟,或者你甚至可以添加一些测试钩子。
最后但并非最不重要的是,您的代码对我来说看起来不太难理解。使用mocks的代码通常很难理解。幸运的是,Python嘲笑比其他语言更容易和更清晰。