1

单元测试--Clean Code

1. 什么是单元测试?(what)

单元测试,是指对软件中的最小可测试单元进行检查和验证。

开发者编写一小段代码,用于检测被测代码的一个很小的、很明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件下某个特定函数的行为。

所以我们可以理解为,单元测试不关注被测函数的所处位置,前置或后置条件,关注仅关注函数的本身。

2. 为什么需要单元测试?(why)

  1. 保证程序在提交版本库之前是完全正确的

  2. bug隐藏的时间约长,修复bug的代价越大

  3. 具有回归性,可以快速的进行回归测试

  4. 为重构提供保障

3. 单元测试如何验证?(how)

1.函数有输出结果时:验证函数的输入输出结果
2.在没有输出结果的时候,分为两种情况:
(1)判断函数是否对某些特定值进行修改,对特定值进行验证
(2)判断函数是否调用第三方库或方法,对第三方库进行mock,然后验证是否调用

4. TDD测试驱动开发 (when)

测试代码与生产代码一起编写,测试只比生产代码早写几秒钟。

开发过程如下:

1.明确当前要完成的功能

2.快速完成针对此功能的测试用例编写
3.测试代码编译不通过
4.编写对应的功能代码
5.测试通过
6.对代码进行重构,并保证测试通过
7.循环完成所有功能的开发

//测试代码
public class HikerTest {
    @Test
    public void life_the_universe_and_everything() {
        int expected = 42;
        int actual = Hiker.answer();
        assertEquals(expected, actual);
    }
}

//生产代码
public class Hiker {
    public static int answer() {
        return 6 * 9;
    }
}

TDD三个测试准则

写代码只为修复失败了的测试

  1. 在写代码之前先写一个失败的单元测试代码

  2. 只可编写刚好无法通过的单元测试,不能编译也算不通过

  3. 只编写刚好足以通过当前失败测试的功能代码

使用TDD开发,会写很多小的自动化测试,这些测试最终会组成一个有效的预警系统以防止代码蜕化。

5. 保持测试整洁

测试必须随着生产代码的演进而修改,测试越脏,就越难修改。
测试代码和生产代码一样重要,它应该和生产代码一样保持整洁。

什么是整洁的测试?
三个要素:可读性、可读性和可读性。
在单元测试中,可读性是重中之重。要求和生产代码一样:明确,简洁,还有足够的表达力。

测试的三个模块?
Given--构造测试数据
When--操作测试数据
Then--检验操作是否得到预期结果

6. 每个测试一个断言

有人认为,每个测试函数都应该有且仅有一个断言语句。单个断言是个好准则,但是最好的做法是单个测试中的断言数量应该最小化。

每个测试是指每个测试函数针对一个测试用例。

例:在一个函数中,流程图如下

st=>start: 
cond=>condition: Yes or No?
sub=>subroutine: Your Subroutine
e=>end

st->cond
cond(yes)->e
cond(no)->sub->io

测试用例应该有两个:

void testNo()
{
}

void testYes()
{
}

7. 整洁的测试准则

  • 快速:测试应该够快,能快速运行。运行缓慢的测试不是单元测试。

  • 独立:测试应该相互独立。不能依赖于其他测试模块,执行顺序等第三方条件。(当测试互相依赖时,一个有缺陷的模块会导致一连串的测试失败)

  • 可重复:测试可以在任何环境中重复通过。(生产环境,断网,质检环境等)

  • 自足验证:测试应当有布尔值输出。不论通过或者失败,不应该查看日志来确认是否通过,以及手工对比文件来确认测试是否通过。

  • 及时:测试应及时编写。单元测试应恰好在使其通过的生产代码之前编写。如果在完成之后编写,会发现生产代码难以测试,甚至不可能去测试。

8. 重构

开发周期的最后一个过程叫做重构。

重构:在不改变系统外部行为的前提下,改善它的内部结构。重构时不仅不能引入缺陷,也不能添加新功能。重构应该保持系统原有的行为。

重构是TDD测试-开发-重构的最后一步。使用TDD而不重构能迅速产生大量的烂代码。无论有多么充足的测试,烂代码终归是烂代码。优良的代码质量能保证今后的开发效率,所以重构必不可少。

9.测试问题

如何测试私有方法?

通过设计测试用例,测试调用私有方法的共有方法,来实现对私有方法的测试。

如何解决对第三方库的依赖?

在方法中若需要使用第三方库或其他函数,可以使用mock工具解决依赖

一个类中是否所有的方法都需要测试?

构造函数不需要测试,getter,setter方法也不需要测试。其他的不论简单与否都应该有测试用例覆盖。

单元测试的测试用例设计

白盒测试主要针对程序的逻辑结构设计测试用例,逻辑单位主要有:语句,分支,条件,路径等。
简单一点的讲,最少的测试用例来最大化满足条件覆盖,分支覆盖,和路径覆盖。


流云
323 声望15 粉丝