wip-1.4
zero1.4 What makes a successful test suite?
1.4 什么样的测试套件才算成功?
I’ve spent most of this chapter discussing improper ways to measure the quality of a test suite: using coverage metrics. What about a proper way? How should you measure your test suite’s quality? The only reliable way is to evaluate each test in the suite individually, one by one. Of course, you don’t have to evaluate all of them at once; that could be quite a large undertaking and require significant upfront effort. You can perform this evaluation gradually. The point is that there’s no automated way to see how good your test suite is. You have to apply your personal judgment.
本章大部分内容都在讨论衡量测试套件质量的不恰当方式:使用覆盖率指标。那么恰当方式是什么?你应该如何衡量测试套件质量?唯一可靠的方式,是逐个评估测试套件中的每个测试。当然,你不必一次性评估所有测试;那可能是一项很大的工作,需要大量前期投入。你可以逐步进行这种评估。重点在于:没有自动化方式能告诉你测试套件到底有多好。你必须运用自己的判断。
Let’s look at a broader picture of what makes a test suite successful as a whole. (We’ll dive into the specifics of differentiating between good and bad tests in chapter 4.) A successful test suite has the following properties:
我们从更宏观的角度看看,整体上什么造就一个成功的测试套件。(第 4 章会深入讨论如何区分好测试和坏测试。)成功的测试套件具有以下属性:
- It’s integrated into the development cycle.
它被集成到开发周期中。 - It targets only the most important parts of your code base.
它只针对代码库中最重要的部分。 - It provides maximum value with minimum maintenance costs.
它以最低维护成本提供最大价值。
1.4.1 It’s integrated into the development cycle
1.4.1 它被集成到开发周期中
The only point in having automated tests is if you constantly use them. All tests should be integrated into the development cycle. Ideally, you should execute them on every code change, even the smallest one.
拥有自动化测试的唯一意义在于你会持续使用它们。所有测试都应该集成到开发周期中。理想情况下,每一次代码变更,即使是最小的变更,你都应该执行测试。
1.4.2 It targets only the most important parts of your code base
1.4.2 它只针对代码库中最重要的部分
Just as all tests are not created equal, not all parts of your code base are worth the same attention in terms of unit testing. The value the tests provide is not only in how those tests themselves are structured, but also in the code they verify.
正如并非所有测试都生来平等,代码库中的所有部分在单元测试方面也并不值得同等关注。测试提供的价值不仅取决于测试本身如何组织,也取决于它们验证的代码。
It’s important to direct your unit testing efforts to the most critical parts of the system and verify the others only briefly or indirectly. In most applications, the most important part is the part that contains business logic—the domain model. Testing business logic gives you the best return on your time investment.
把单元测试精力投向系统中最关键的部分,并对其他部分只做简要或间接验证,这很重要。在大多数应用中,最重要的部分是包含业务逻辑的部分,也就是领域模型。测试业务逻辑能让你的时间投入获得最佳回报。
All other parts can be divided into three categories:
所有其他部分可以分为三类:
- Infrastructure code
基础设施代码。 - External services and dependencies, such as the database and third-party systems
外部服务和依赖,例如数据库和第三方系统。 - Code that glues everything together
把所有东西粘合在一起的代码。
Some of these other parts may still need thorough unit testing, though. For example, the infrastructure code may contain complex and important algorithms, so it would make sense to cover them with a lot of tests, too. But in general, most of your attention should be spent on the domain model.
不过,这些其他部分中的某些部分仍然可能需要充分的单元测试。例如,基础设施代码可能包含复杂且重要的算法,因此用大量测试覆盖它们也是合理的。但总体来说,你的大部分注意力应该放在领域模型上。
Some of your tests, such as integration tests, can go beyond the domain model and verify how the system works as a whole, including the noncritical parts of the code base. And that’s fine. But the focus should remain on the domain model.
你的一些测试,例如集成测试,可以超出领域模型范围,验证系统作为一个整体如何工作,包括代码库中不那么关键的部分。这没问题。但焦点仍然应该留在领域模型上。
Note that in order to follow this guideline, you should isolate the domain model from the non-essential parts of the code base. You have to keep the domain model separated from all other application concerns so you can focus your unit testing efforts on that domain model exclusively. We talk about all this in detail in part 2 of the book.
注意,为了遵循这条原则,你应该把领域模型与代码库中非核心部分隔离开。你必须让领域模型与所有其他应用关注点分离,这样才能把单元测试精力专注于领域模型本身。我们会在本书第 2 部分详细讨论这些内容。
See Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric Evans (Addison-Wesley, 2003).
参见 Eric Evans 的《Domain-Driven Design: Tackling Complexity in the Heart of Software》(Addison-Wesley,2003)。
1.4.3 It provides maximum value with minimum maintenance costs
1.4.3 它以最低维护成本提供最大价值
The most difficult part of unit testing is achieving maximum value with minimum maintenance costs. That’s the main focus of this book.
单元测试中最困难的部分,是以最低维护成本实现最大价值。这正是本书的主要关注点。
It’s not enough to incorporate tests into a build system, and it’s not enough to maintain high test coverage of the domain model. It’s also crucial to keep in the suite only the tests whose value exceeds their upkeep costs by a good margin.
把测试纳入构建系统还不够;保持领域模型的高测试覆盖率也不够。同样关键的是,测试套件中只保留那些价值明显超过维护成本的测试。
This last attribute can be divided in two:
最后这个属性可以分为两部分:
- Recognizing a valuable test (and, by extension, a test of low value)
识别有价值的测试,并进一步识别低价值测试。 - Writing a valuable test
写出有价值的测试。
Although these skills may seem similar, they’re different by nature. To recognize a test of high value, you need a frame of reference. On the other hand, writing a valuable test requires you to also know code design techniques. Unit tests and the underlying code are highly intertwined, and it’s impossible to create valuable tests without putting significant effort into the code base they cover.
虽然这些能力看起来相似,但本质上并不相同。要识别高价值测试,你需要一套参照框架。另一方面,要写出有价值的测试,你还需要了解代码设计技术。单元测试和底层代码高度交织;如果不对被测试覆盖的代码库投入大量精力,就不可能创建有价值的测试。
You can view it as the difference between recognizing a good song and being able to compose one. The amount of effort required to become a composer is asymmetrically larger than the effort required to differentiate between good and bad music. The same is true for unit tests. Writing a new test requires more effort than examining an existing one, mostly because you don’t write tests in a vacuum: you have to take into account the underlying code. And so although I focus on unit tests, I also devote a significant portion of this book to discussing code design.
你可以把它看作“识别一首好歌”和“能够创作一首好歌”之间的差异。成为作曲家所需的努力,要远远大于区分好音乐和坏音乐所需的努力。单元测试也是如此。编写一个新测试比检查一个现有测试需要更多努力,主要是因为你不是在真空中写测试:你必须考虑底层代码。因此,虽然本书关注单元测试,但我也会用相当篇幅讨论代码设计。