Unit testing


1. 概念

In computer programming, unit testing is a software testing method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine whether they are fit for use. Intuitively, one can view a unit as the smallest testable part of an application. In procedural programming, a unit could be an entire module, but it is more commonly an individual function or procedure. In object-oriented programming, a unit is often an entire interface, such as a class, but could be an individual method. Unit tests are short code fragments created by programmers or occasionally by white box testers during the development process. It is also known as component testing.
在计算机编程中,单元测试是一种软件测试方式。它用来测试:源代码的片段,一个或多个计算机程序模块的集合(包括这些模块的控制数据、程序手册和操作手册)。以便确定测试对象是否可以正确使用。
Ideally, each test case is independent from the others. Substitutes such as method stubs, mock objects, fakes, and test harnesses can be used to assist testing a module in isolation. Unit tests are typically written and run by software developers to ensure that code meets its design and behaves as intended.
理想情况下,每个单元测试用例都是独立的。桩方式、仿真对象、仿制数据和其它测试手段,可以帮助将一个模块隔离出来进行测试。单元测试用例通常由软件开发人员实现和执行,以确定测试代码是否满足设计要求,以及其结果是否与预期一致。

2. 作用

The goal of unit testing is to isolate each part of the program and show that the individual parts are correct. A unit test provides a strict, written contract that the piece of code must satisfy. As a result, it affords several benefits.
单元测试的目标是隔离程序的每个部件并且证明这些部件孤立情况下是正确的。单元测试提供了代码片段必须满足的严格的书面协议。因此,它有以下几大好处。

2.1. 更早发现问题

Unit testing finds problems early in the development cycle.
单元测试能够在开发周期中更早的发现问题。
In test-driven development (TDD), which is frequently used in both Extreme Programming and Scrum, unit tests are created before the code itself is written. When the tests pass, that code is considered complete. The same unit tests are run against that function frequently as the larger code base is developed either as the code is changed or via an automated process with the build. If the unit tests fail, it is considered to be a bug either in the changed code or the tests themselves. The unit tests then allow the location of the fault or failure to be easily traced. Since the unit tests alert the development team of the problem before handing the code off to testers or clients, it is still early in the development process.
在测试驱动的开发中(TDD,常在极限编程和敏捷开发中使用),单元测试要比代码本身更早创建。只有当所有测试用例都通过了,代码才被认为是完成的。无论是当大代码库开发完成,还是当代码发生变更或通过自动化编译时,相同的单元测试都会被运行,以验证功能的正确。如果单元测试失败了,那么要么是变更的代码有bug,要么测试本身有bug。单元测试能够更容易地追踪和定位错误或缺失。单元测试能够在代码提交到测试人员或客户前,就能够告知开发组代码所存在的问题,显然这在开发进程还处于很前期。

3.2. 适应变更

Unit testing allows the programmer to refactor code at a later date, and make sure the module still works correctly (e.g., in regression testing). The procedure is to write test cases for all functions and methods so that whenever a change causes a fault, it can be quickly identified.
单元测试允许程序员在后期重构代码,同时确保模块仍然正确工作(例如回归测试)。这个程序就是要求你对所有功能和方法完成对应的测试用例。这样无论什么时候,由于变更引起的问题,都能够被快速发现。
Readily available unit tests make it easy for the programmer to check whether a piece of code is still working properly.
对于程序员来说,简洁有效的单元测试能够非常方便地检查代码片段是否仍然正确工作。
In continuous unit testing environments, through the inherent practice of sustained maintenance, unit tests will continue to accurately reflect the intended use of the executable and code in the face of any change. Depending upon established development practices and unit test coverage, up-to-the-second accuracy can be maintained.
在连续的单元测试环境里,通过其持续维持的固有测试,单元测试一直精确地反映出可执行程序和代码的预期的结果,无论发生任何变更。借助于已经建立的开发实践和单元测试的覆盖率,可以分分秒秒维持准确性。

2.3. 简化集成

Unit testing may reduce uncertainty in the units themselves and can be used in a bottom-up testing style approach. By testing the parts of a program first and then testing the sum of its parts, integration testing becomes much easier.
单元测试可以降低程序单元的不确定性,一种有效途径是通过自底向上的测试方式达到。先测试程序各个独立的小部分,再将这些小部分组合起来测试,这样集成测试变得更加简单。
An elaborate hierarchy of unit tests does not equal integration testing. Integration with peripheral units should be included in integration tests, but not in unit tests. Integration testing typically still relies heavily on humans testing manually; high-level or global-scope testing can be difficult to automate, such that manual testing often appears faster and cheaper.
在测试分层体系结构里,单元测试有别于集成测试。外围单元集成进来测试应该包含在集成测试用例,而不是单元测试用例。集成测试通常很依赖于人工手动测试;高等级或全局性的测试要做到自动化非常困难,而手动测试反而非常快捷和便宜。

2.4. 文档化

Unit testing provides a sort of living documentation of the system. Developers looking to learn what functionality is provided by a unit, and how to use it, can look at the unit tests to gain a basic understanding of the unit's interface (API).
单元测试提供一系列真实的本系统的文档。借此,开发者可以指导单元提供了哪些功能,以及如何使用,同时可以通过查阅单元测试用例,对单元的接口(API)形成初步的认识。
Unit test cases embody characteristics that are critical to the success of the unit. These characteristics can indicate appropriate/inappropriate use of a unit as well as negative behaviors that are to be trapped by the unit. A unit test case, in and of itself, documents these critical characteristics, although many software development environments do not rely solely upon code to document the product in development.
单元测试用例包含了程序单元成功的关键特征。这些特征可以指出正确使用和非正确使用程序单元,也能指出程序单元诱导的负面表现。尽管许多软件开发环境在开发过程中不仅仅依靠代码作为产品文档,单元测试用例本身就文档化这些特征。

3.5. 设计

When software is developed using a test-driven approach, the combination of writing the unit test to specify the interface plus the refactoring activities performed after the test is passing, may take the place of formal design. Each unit test can be seen as a design element specifying classes, methods, and observable behaviour. The following Java example will help illustrate this point.
在测试驱动的软件开发模式下,将详细描述接口的书面的单元测试用例和测试通过的重构表征结合在一起,可以用来取代正式的设计。每个单元测试用例可以看作是一个设计元素-详细描述类、方法和可见的行为。
以下Java例子可以用来阐明这个观点。
Here is a set of test cases that specify a number of elements of the implementation. First, that there must be an interface called Adder, and an implementing class with a zero-argument constructor called AdderImpl. It goes on to assert that the Adder interface should have a method called add, with two integer parameters, which returns another integer. It also specifies the behaviour of this method for a small range of values over a number of test methods.
这是一个证明一批实现设计元素的测试类。首先,必须要有一个称为Adder的接口,和一个叫做AdderImpl的不带参数的构造函数。然后,它断言Adder接口包含有一个带有两个整数参数,并且返回值为整型的add方法。它也通过小范围的值检验说明方法的行为。
public class TestAdder {
 
    // can it add the positive numbers 1 and 1?
    public void testSumPositiveNumbersOneAndOne() {
        Adder adder = new AdderImpl();
        assert(adder.add(1, 1) == 2);
    }
 
    // can it add the positive numbers 1 and 2?
    public void testSumPositiveNumbersOneAndTwo() {
        Adder adder = new AdderImpl();
        assert(adder.add(1, 2) == 3);
    }
 
    // can it add the positive numbers 2 and 2?
    public void testSumPositiveNumbersTwoAndTwo() {
        Adder adder = new AdderImpl();
        assert(adder.add(2, 2) == 4);
    }
 
    // is zero neutral?
    public void testSumZeroNeutral() {
        Adder adder = new AdderImpl();
        assert(adder.add(0, 0) == 0);
    }
 
    // can it add the negative numbers -1 and -2?
    public void testSumNegativeNumbers() {
        Adder adder = new AdderImpl();
        assert(adder.add(-1, -2) == -3);
    }
 
    // can it add a positive and a negative?
    public void testSumPositiveAndNegative() {
        Adder adder = new AdderImpl();
        assert(adder.add(-1, 1) == 0);
    }
 
    // how about larger numbers?
    public void testSumLargeNumbers() {
        Adder adder = new AdderImpl();
        assert(adder.add(1234, 988) == 2222);
    }
}
In this case the unit tests, having been written first, act as a design document specifying the form and behaviour of a desired solution, but not the implementation details, which are left for the programmer. Following the "do the simplest thing that could possibly work" practice, the easiest solution that will make the test pass is shown below.
在这个例子中,单元测试用例先实现,可以作为一个设计文档,用来描述一个期望的解决方案的构成和行为,但不涉及到具体实现细节,这些留给程序员考虑。遵循“做最简单的事情”的实践准则,下面最简单的解决方案可以通过上述测试。
interface Adder {
    int add(int a, int b);
}
class AdderImpl implements Adder {
    int add(int a, int b) {
        return a + b;
    }
}
Unlike other diagram-based design methods, using unit-tests as a design specification has one significant advantage. The design document (the unit-tests themselves) can be used to verify that the implementation adheres to the design. With the unit-test design method, the tests will never pass if the developer does not implement the solution according to the design.
不同于其他基于图的设计方法,用单元测试表达设计有一项显著优点:设计文档(单元测试本身)可以用于验证程序实现符合设计。基于单元测试设计方法,开发人员不遵循设计要求实现的解决方案永远不会通过测试。
It is true that unit testing lacks some of the accessibility of a diagram, but UML diagrams are now easily generated for most modern languages by free tools (usually available as extensions to IDEs). Free tools, like those based on the xUnit framework, outsource to another system the graphical rendering of a view for human consumption.
当然,单元测试缺乏图的某些容易传达的特性,但是UML图可以在自由工具(通常可从IDE扩展获取)中为大多数现代程序语言生成。自由工具,类似于基于xUnit框架的工具,测试结果输出到一些可生成供人工识读的图形化工具系统中去。

后续添加Unit testing tools的介绍

阅读更多
换一批

没有更多推荐了,返回首页