wip-6.1

2026-06-05 ⏳1.2分钟(0.5千字)

6.1 The three styles of unit testing

6.1 三种单元测试风格

As I mentioned in the chapter introduction, there are three styles of unit testing:

正如本章导言中提到的,单元测试有三种风格:

You can employ one, two, or even all three styles together in a single test. This section lays the foundation for the whole chapter by defining (with examples) those three styles of unit testing. You’ll see how they score against each other in the section after that.

你可以在单个测试中使用其中一种、两种,甚至三种风格都一起使用。本节会通过定义和示例说明这三种单元测试风格,为整章奠定基础。在下一节中,你会看到它们彼此之间如何评分比较。

6.1.1 Defining the output-based style

6.1.1 定义基于输出的风格

The first style of unit testing is the output-based style, where you feed an input to the system under test (SUT) and check the output it produces (figure 6.1). This style of unit testing is only applicable to code that doesn’t change a global or internal state, so the only component to verify is its return value.

第一种单元测试风格是基于输出的风格:你向被测系统(SUT)提供输入,并检查它产生的输出(图 6.1)。这种单元测试风格只适用于不会改变全局状态或内部状态的代码,因此唯一需要验证的组成部分就是它的返回值。

Figure 6.1

The following listing shows an example of such code and a test covering it. The PriceEngine class accepts an array of products and calculates a discount.

下面的清单展示了这类代码以及覆盖它的测试。PriceEngine 类接收一个商品数组并计算折扣。

Listing 6.1

PriceEngine multiplies the number of products by 1% and caps the result at 20%. There’s nothing else to this class. It doesn’t add the products to any internal collection, nor does it persist them in a database. The only outcome of the CalculateDiscount() method is the discount it returns: the output value (figure 6.2).

PriceEngine 将商品数量乘以 1%,并把结果上限限制为 20%。这个类没有做其他事情。它不会把商品添加到任何内部集合中,也不会把它们持久化到数据库。CalculateDiscount() 方法唯一的结果就是它返回的折扣:也就是输出值(图 6.2)。

Figure 6.2

The output-based style of unit testing is also known as functional. This name takes root in functional programming, a method of programming that emphasizes a preference for side-effect-free code. We’ll talk more about functional programming and functional architecture later in this chapter.

基于输出的单元测试风格也被称为函数式。这一名称源自函数式编程;函数式编程是一种强调偏好无副作用代码的编程方法。本章后面会更多讨论函数式编程和函数式架构。

6.1.2 Defining the state-based style

6.1.2 定义基于状态的风格

The state-based style is about verifying the state of the system after an operation is complete (figure 6.3). The term state in this style of testing can refer to the state of the SUT itself, of one of its collaborators, or of an out-of-process dependency, such as the database or the filesystem.

基于状态的风格关注的是在某个操作完成后验证系统状态(图 6.3)。这种测试风格中的“状态”可以指 SUT 自身的状态、某个协作者的状态,也可以指出进程依赖的状态,例如数据库或文件系统。

Figure 6.3

Here’s an example of state-based testing. The Order class allows the client to add a new product.

下面是一个基于状态测试的示例。Order 类允许客户端添加一个新商品。

Listing 6.2

The test verifies the Products collection after the addition is completed. Unlike the example of output-based testing in listing 6.1, the outcome of AddProduct() is the change made to the order’s state.

该测试在添加完成后验证 Products 集合。与清单 6.1 中基于输出的测试示例不同,AddProduct() 的结果是订单状态发生了变化。

6.1.3 Defining the communication-based style

6.1.3 定义基于通信的风格

Finally, the third style of unit testing is communication-based testing. This style uses mocks to verify communications between the system under test and its collaborators (figure 6.4).

最后,第三种单元测试风格是基于通信的测试。这种风格使用 mock 来验证被测系统与其协作者之间的通信(图 6.4)。

Figure 6.4

The following listing shows an example of communication-based testing.

下面的清单展示了一个基于通信测试的示例。

Listing 6.3

Styles and schools of unit testing
The classical school of unit testing prefers the state-based style over the communication-based one. The London school makes the opposite choice. Both schools use output-based testing.

单元测试风格与学派 经典学派的单元测试更偏好基于状态的风格,而不是基于通信的风格。伦敦学派则做出相反选择。这两个学派都会使用基于输出的测试。