可以看到,测试脚本并不直接与系统的UI交互,而是通过客户端驱动层交互。这样测试用例便可以从与UI的耦合中解放出来,使用跟业务更接近的方式编写,如下面的测试用例:

def test_testSearchEngineInput(self):
    seTest = SearchEngineProxy()
    seTest.submitTestText('Test')
    result = seTest.getSearchEngineTitle()
    self.assertTrue('Test' in result)

  可以看到,上面的代码没有与UI交互相关的代码,而是从业务场景的角度,提交文本到搜索引擎(submitTestText),获取搜索结果的标题(getSearchEngineTile),后验证标题的正确性。所有与UI层交互都被封装到了客户端驱动(SearchEngineProxy)中。顺便提一个,我们也可以使用单元测试框架编写自动化功能测试,比如的xUnit系列。

  客户端驱动层则是一个由测试人员与开发人员共同完成的模块。如果需要简单分工的话,可以由测试人员负责设计接口,由开发人员负责实现。这样由于UI变更造成的影响便全部落到了开发人员的工作范围内,从而减少各种沟通和变更的成本。在客户端驱动层,上一篇博客(论程序员的自我修养——自动化功能测试)中提到的自动化测试工具有用武之地了,这是为什么程序员也需要学会选择自动化测试工具。

  选择适当的模式

  我无法评价上面两种模式的优劣,对于不同的项目,更应该根据项目的情况加以选择。相信不少程序员一边看客户端驱动模式,一边会皱眉头。谁都不想多维护一个模块的代码,客户端驱动模式也是一种对耦合的妥协,如果系统UI相对简单,通过简单的手工测试也可以发现UI显示逻辑中的bug,可以直接通过公用API进行自动化测试了。

  但总有复杂的UI,需要通过自动化测试把UI层也进行测试,这个时候也别为了方便,直接让测试脚本与UI进行交互。毕竟测试脚本不总是由开发人员维护,与UI紧密耦合的测试脚本可能会让测试用例经常失败,严重打击团队的积极性和自动化测试结果的权威性,让自动化测试无法有效地执行下去。