测试GUI代码:我应该使用模拟库吗?

8 投票
3 回答
1402 浏览
提问于 2025-04-11 09:17

最近,我在用Python开发一个图形用户界面应用时,开始尝试测试驱动开发(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的核心原则,以至于我的测试毫无意义?

3 个回答

-3

请记住,测试驱动开发(TDD)并不是万能的解决方案。 这很难,确实应该很难,特别是提前写出模拟测试更是挑战。

所以我想说,做适合你的事情就好。即使这不是“认证的TDD”,我基本上也是这么做的。

你可以考虑为图形用户界面(GUI)提供一个自己的接口,这个接口可以放在控制器代码和GUI库代码之间。这样可能更容易进行模拟测试,或者你甚至可以在里面添加一些测试钩子。

最后,你的代码在我看来并不是特别难懂。使用模拟的代码通常更难理解。幸运的是,在Python中,模拟测试比在其他语言中要简单和清晰得多。

-1

单元测试在你重构代码的时候特别有用(也就是完全重写或者移动一个模块)。只要在你进行大改动之前有了单元测试,你就可以放心,因为这样可以确保你在完成后没有遗漏什么东西。

8

如果你是在写完代码后再写测试,并让测试通过,那你就不是在做测试驱动开发(TDD)(也没有享受到先写测试或测试驱动开发的好处……可以查查StackOverflow上的问题,找找关于TDD的经典书籍)

我发现使用mock(模拟)工具时,先写应用代码再写测试代码更容易。因为大多数情况下,我需要模拟很多方法调用,而写这些模拟调用的语法比写应用代码要复杂得多(所以更难写)。所以,先写应用代码,然后再根据它来写测试代码会简单很多。

当然,这样做简单是因为你只是测试在用特定的刷子把天空涂成橙色之后,天空确实是橙色的。这就是在事后加测试(为了自我安慰)。模拟工具很好,但你要知道怎么用、什么时候用——就像那句老话:“有锤子就觉得什么都是钉子。”同时,也很容易写出一堆难以理解且不够有用的测试。花时间去理解测试的内容,其实是浪费了本可以用来修复坏测试的时间。

重点是:

  • 如果你还没看过,建议阅读Mocks aren't stubs - Martin Fowler。可以在网上找一些关于好的ModelViewPresenter模式的图形用户界面(如果需要,可以虚拟/模拟用户界面)。
  • 研究你的选择,明智地选择。我会在你左肩上扮演一个天使,告诉你“别这样做。”可以看看这个问题,了解我的理由——圣贾斯丁在你右肩上,我相信他也有话要说:)

撰写回答