TDD的核心:Specification by Example

原文:Specification by Example

作者:Martin Flower 

 

[Martin Fowler这篇文章点出了TDD的核心理念:Specification by Example,即测试用例(Test Case)是一种通过例子(Example)来表达需求的规范(Specification)形式。]

I was attending a workshop at XP/Agile Universe in 2002 when the phrase 'Specification By Example' struck me as a way to describe one of roles of testing in XP.

(These days it's terribly unfashionable to talk about Test Driven Development (TDD) having anything to do with testing, but like Jon I do think that having a comprehensive automated test suite is more valuable than the term 'side-effect' implies. Rather like if someone offered me a million dollars to hike up a mountain. I may say that the main purpose of the hike is the enjoyment of nature, but the side-effect to my wallet is hardly trivial....)

Specification By Example isn't the way most of us have been brought up to think of specifications. Specifications are supposed to be general, to cover all cases. Examples only highlight a few points, you have to infer the generalizations yourself. This does mean that Specification By Example can't be the only requirements technique you use, but it doesn't mean that it can't take a leading role.

[传统的需求规范一般是通用的,覆盖所有场景的,比如:自然语言描述的文档;而TDD则用把测试用例作为主要的需求规范形式。由于测试用例不具备通用性(General),所以它不能作为唯一的规范形式,但这也不妨碍它成为一种主要的形式。与文档相比,测试用例更加精确(Precise),更易于获得反馈(Quick Feedback),更贴近真实用户(User Friendly),更加稳定(Stable)]

So far the dominant idea with rigorous specifications, that is those that can be clearly judged to be passed or failed, is to use pre and post conditions. These techniques dominate in formal methods, and also underpin Design by Contract. These techniques have their place, but they aren't ideal. The pre-post conditions can be very easy to write in some situations, but others can be very tricky. I've tried to use them in a number enterprise application settings, and I've found that in many situations it's as hard to write the pre and post conditions as it is to write the solution. One of the great things about specification by example is that examples are usually much easier to come up with, particularly for the non-nerds who we write the software for. (Timothy Budd pointed out that while you can show a lot of stack behavior with pre and post conditions, it's very tricky to write pre and post conditions that show the LIFO property.)

[关于需求规范形式的探索,大致分为两条路:一条是形式化方法(Formal Method),一条是Specification by Example。形式化方法的代表是Design by Contract,即从契约(Contract)的角度思考对象的行为,为每个public方法都加上Precondition/Postcondition/Invariant。形式化方法具备文档的通用性,又具有测试用例的精确性,但是其缺点是需要比较高的技巧,比如:把StackLIFO表达成Precondition/Postcondition/Invariant需要很triky的手段。而TDD为代表的Specification by Example理论上不如Design by Contract漂亮,但实践上很管用,对人的要求并不高。另外,形式化方法之所以有时难以实现也和语言范式有关,因为Precondition/Postcondition/Invariant的检验(ASSERT)都要求是无副作用的(Side Effect);所以,在函数式编程中,形式化方法比命令式和OOP要容易得多。]

An important property of TDD tests is that they involve a double-check. In fact this highlights an amusing little lie of the XP community. They make a very strong point of saying things Once and Only Once, but in fact they always say things twice: once in the code and once in the tests. Kent has pointed out that this double-check principle is a vital principle, and it's certainly one that humans use all the time. The value of the double check is very much tied into using different methods for each side of the double check. Combining Specification By Example with production code means that you have both things said quite differently, which increases their ability to find errors.

The formal specification community have constantly had trouble verifying that a design satisfies a specification, particularly in doing this without error prone humans. For Specification By Example, this is easy. Another case of Specification By Example being less valuable in theory but more valuable in practice.

One Design by Contract fan pointed out that if you write a specification in terms of tests, then the supplier could satisfy the specification by just returning hard-coded responses to the specific test inputs. My flippant answer to this is that if you are concerned about this then the issue of tests versus Design by Contract is the least of your worries. But there is a serious point here. Tests are always going to be incomplete, so they always have to be backed up with other mechanisms. Being the twisted mind that I am, I actually see this as a plus. Since it's clear that Specification By Example isn't enough, it's clear that you need to do more to ensure that everything is properly communicated. One of the most dangerous things about a traditional requirements specification is when people think that once they've written it they are done communicating.

Specification By Example only works in the context of a working relationship where both sides are collaborating and not fighting. The examples trigger abstractions in the design team while keeping the abstractions grounded. You do need more - things like regular conversation, techniques like Domain Driven Design, indeed even doses of Design by Contract. While I've never had the opportunity to use Design by Contract fully (i.e. with Eiffel) I regularly think about interfaces in contractual terms. Specification By Example is a powerful tool, perhaps my most used tool, but never my only tool.

[Martin Flower谈到不能仅仅依靠Specification by Example就够了,也不适合在一个特别严格的环境下去证明程序的正确性,它更适合在一个合作、友好、沟通顺畅的环境下使用。]

(For more thinking on Specification By Example, if not by that name, take a look at Brian Marick's writings. Somewhere on his site there probably is one super page that sums up his view on it. Of course finding it is less valuable than reading all the stuff there while you're trying)

posted on 2010-11-11 11:04  Todd Wei  阅读(2672)  评论(2编辑  收藏  举报