单元测试很棒。在假定一些数据的环境下,能顺利通过测试的系统就可算是一个好系统。
不过,现在可以直连外部资源的集成测试才让程序更有价值。谁知道那些内容商(供应商,vendor)会做出什么傻事来!
很多人一直尝试着让测试达到100%的代码覆盖率,这是很棒的想法,但我倒觉得它有些基本概念上的问题。
LosTechies,
Ryan
Svihla 提出了"反模式(anti-pattern", 有个有趣的观点: “多数应用都需要与外部资源交互”。他们有许多不错的论点,比如:
大多数的单元测试都需一个运行着的数据库、网页或应用服务器。
确实如此。
全是同数据和外部系统相关的
我下面将要证明多数Bug并不来源于程序本身,而是由从外部输入的数据所引起的。
为什么? 因为通常Bug出现在实际的工作环境中,我们的程序总会处理不好那些外部系统输入的原始数据,或者程序输出到外部系统中的数据。而"单元测试"或TDD中所强调的是提供一组假定的数据,检验程序是否能够按照预期的方式运行。也就说整个测试是在一个假定环境下进行的。这就是为什么接口总是如此轻易就成功运行了。在这之上还可以达到自动化,预测试性,以及可重复的测试。但是仍有很多系统无法解决现实的问题。
因为这样的测试方式所能解决的仅是软件开发要面对的问题中的一部分。如何才能发现真正的问题?最终还是要让你的软件与它的外部资源连接起来运行才能发现。
举个略为抽象的例子:
1) 一些来自外部系统的数据.
2) 应用程序开始处理这些数据.
3) 应用程序将处理后的数据发送到外部资源中 (一般是与第1步不同的数据)
4) 外部数据拿到第3步的数据,在处理后再发送到应用程序.
5) 再次接收到数据,并加以处理.
如此反复。
我们常用mocks/stubs或者类似的程序来产生第1步的数据来进行第2步的测试,而测试第5步时所使用的数据也是使用类似的方式产生的。其中第1步和第4步是不可靠,也是不可预计的,因为你根本不知道外部系统会给你什么数据。
第1步和第4步是程序在上线环境下要面对的,所以它们才是最需要关注的。
外部系统都很挑剔( External systems are finicky mean things)
对于一些e-Commerce系统,或者财务系统,各式的接口,各式的数据在各个系统间流转。
我们来谈一些高层次的问题:
1)理想情况下,当外部系统更改了要发送的数据,无论是是格式(format)或模式(schema),你希望会提前知道。这有些一厢情愿了。最近我曾与一个电子商务系统,外部数据系统的税务信息增加了一栏,同时需要应用程序调整内部逻辑。就是外部数据系统已经开始发送数据了,我们才知道的。
2)理想情况下,当外部系统声称支持新的API,你应该改变应用程序的内部逻辑,并且发送新数据。最后,你会发现,他们支持新的API,要么在他们的UAT(User Acceptance Test)环境而不在上线(PRODUCTION)的环境,或者只在上线环境中而不在UAT环境中。
3)你的程序已使用关于国内资产的采购信息很顺畅了,外部系统和程序的配合也很好。然后开始加入一些国际资产信息时,你可能并不能及时地发现数据已完全变了。
这些都是我曾遇到的场景。我要说就是你在单元测试中根据无法了解到未来面对的环境,只有实际运行时才有办法。更悲哀的是那些在凌晨3点把你叫起来的问题通常都这样产生的。
如何完善测试规格(How to setup your Specs)
我做设计也是从规格文档开始的。规格(specification)其实就是另一种测试(well-crafted tests)。我会区分规格中的单元和集成,并写不同的代码。
所谓“单元”的测试规格是测试内部的业务逻辑,看看有没有把东西都串起来了。就是在测试时提供一些场景,确保程序执行正确的逻辑,输出期望的结果。
而集成(Integration)的测试规格则和外部资源有关。直接提供一组外部资源数据,以及要返回的数据。这些是集成测试中实际关心的东西。 和外部资源的交互才能真正确定程序是否可以正常工作。
[只译出主要概念,详细内容请阅读原文!]
作者:HorkyChen 发表于2013-3-18 1:55:42
原文链接