扫盲:什么是单元测试?

互联网大厂的基本开发流程

在这里插入图片描述

大部分公司都是属于应用级软件的开发,在应用软件需求迭代快,变化频繁的背景下,结合实际对人家的要求、人力成本,单元测试的投入产出比并没有想象中的那么好。

一、概念

单元测试是对软件中的基本组成单位(如模块、过程、函数或类)进行的测试,在保障软件质量的过程中发挥着重要作用。
单元测试不能替代系统测试和验收测试,长远来看,单测是能够有效提高工作效率的!可以让软件的bug更少,软件质量保证变得更好.
进行单元测试的好处:

  1. 进行单元测试可以降低测试成本
  2. 进行单元测试可以提升产品质量

单元测试、TDD、BDD的区别

单元测试

单元测试是对软件中的基本组成单位(如模块、过程、函数或类)进行的测试,在保障软件质量的过程中发挥着重要作用。
单元测试不能替代系统测试和验收测试,长远来看,单测是能够有效提高工作效率的!可以让软件的bug更少,软件质量保证变得更好.

TDD 测试驱动开发

编写单测的时机,一般是 The sooner, the better(越早越好)。尽量不要将单测拖延到代码编写完之后,这样带来的收益可能不尽如人意。
TDD(Test-Driven Development)测试驱动开发,是一种软件开发过程中的应用方法,以其倡导先写测试程序,然后编码实现其功能得名。
(理想状态,产品需求往往是可变的)测试驱动着整个开发过程:首先,驱动代码的设计和功能的实现;其后,驱动代码的再设计和重构。
最常见和推荐:边开发边写单测,先写少量功能代码,紧接着写单测,重复这两个过程,直到完成功能代码开发.

BDD 行为驱动开发

BDD是新一代、从外到内、基于拉取、多利益相关的、多规模、高自动化的敏捷方法。它是一个具有明确定义了产出的交互循环,从而实现了正常工作中的、经过测试的软件产品的交付。
BDD(Behavior-Driven Development),鼓励软件项目中的开发人员,测试人员和非技术人员或者客户之间的协作,从用户的需求出发,强调系统行为。
在 TDD 中,我们并不能完全保证根据设计所编写的测试就是用户所期望的功能,用户并一定能看懂测试用例。BDD是基于一种“通用语言”,可以让客户、产品经理等将需求通过同一种语言描述出来,很大程度上避免了因为理解或表达不一致带来的问题,大大提高产品的交付品质。由此BDD的优势也就体现出来了:
● 更关注业务,以用户使用产品的角度,描述用户行为以及预期结果
● 不同角色的人都可以参与需求定义及讨论,最终达成一致理解
● 使用同一种语言描述需求,及测试用例,很大程度上避免了因理解差异导致实现功能与需求不一致的问题
常用的BDD测试框架
● Cucumber:基于Ruby编写的自动化测试框架,支持Java和.Net等多种语言
● Behave/Lettuce/Freshen: Python style的测试框架
● Jbehave/ beanSpec :基于Java编写的自动化测试框架
● SpecFlow:.Net测试框架

二、单元测试适用范围

对代码质量要求高!开发人员水平高!业务需求变动小!

在这里插入图片描述

三、哪些需要进行单元测试?

要求:单测覆盖率越高越好,ROI越高越好
拓展:计算 ROI 有多种方法。最常见的是净收入除以投资总成本,或 ROI = 净收入/投资成本 x 100

四、单元测试编写原则

F-Fast 快速

在开发过程中通常需要随时执行测试用例;在发布流水线中执行也必须执行,常见的就是push代码后,或者打包时先执行测试用例;况且一个项目中往往有成百上千个测试用例。
所以为了保证开发和发布效率,快速执行是单测的重要原则。这就要求我们不要像集成测试一样依赖多个组件,确保单测在秒级甚至毫秒级执行完毕。

自动化测试

I-Isolated 隔离

隔离性也可以理解为独立性,好的单测是每个测试用例只关注一个逻辑单元或者代码分支,保证单一职责,这样能更清晰的暴露问题和定位问题。
每个单测之间不应该产生依赖,为了保证单测稳定可靠且便于维护,单测用例之间决不能互相调用,也不能依赖执行的先后次序。
数据资源隔离,测试时不要依赖和修改外部数据或文件等其他共享资源,做到测试前后共享资源数据一致。

R—Repeatable:可重复执行

单测是可以重复执行的,不能受到外界环境的影响。 同一测试用例,即使是在不同的机器,不同的环境中运行多次,每次运行都会产生相同的结果

S—Self-verifying:自我验证

单测需要通过断言进行结果验证,即当单测执行完毕之后,用来判断执行结果是否和假设一致,无需人工检查是否执行成功。

T—Timely&Thorough:及时,全面

理想情况下每行代码都要被覆盖到,每一个逻辑分支都必须有一个测试用例。即TDD(测试驱动开发)模式开发

五、如何搭建单元测试?

普及Fake、Stub、Mock 概念

Fake:是那些包含了生产环境下具体实现的简化版本的对象。

基于内存的实现,不关注数据本身是否对错,能够迅速地实现系统原型,并且基于内存存储来运行整个系统,推迟有关数据库设计所用到的一些决定。

@Profile("transient")
public class FakeAccountRepository implements AccountRepository {

   Map<User, Account> accounts = new HashMap<>();

   public FakeAccountRepository() {
       this.accounts.put(new User("john@bmail.com"), new UserAccount());
       this.accounts.put(new User("boby@bmail.com"), new AdminAccount());
   }

   String getPasswordHash(User user) {
       return accounts.get(user).getPasswordHash();
   }
}

如:
1.当某个对象需要从数据库抓取数据时,我们并不需要真实地与数据库进行交互,直接从内存中抓去数据,保证业务流程的正常运行.
2.支付场景,永远返回支付成功的结果,去进行后续的业务逻辑测试.

Stub:常被用于我们不希望返回真实数据或者造成其他副作用的场景。

对已知返回数据进行模拟返回,不需要进行具体的业务逻辑;(常用于Query操作)

如:
当某个对象需要从数据库抓取数据时,我们并不需要真实地与数据库进行交互或者像 Fake 那样从内存中抓取数据,而是直接返回预定义好的数据。

// 成绩实现类
public class GradesService {

   private final Gradebook gradebook;

   public GradesService(Gradebook gradebook) {
       this.gradebook = gradebook;
   }

   // 求平均值
   Double averageGrades(Student student) {
       return average(gradebook.gradesFor(student));
   }
}

// 成绩测试类
public class GradesServiceTest {

   private Student student;
   private Gradebook gradebook;

   @Before
   public void setUp() throws Exception {
       gradebook = mock(Gradebook.class);
       student = new Student();
   }

   @Test
   public void calculates_grades_average_for_student() {
        //stubbing gradebook
       when(gradebook.gradesFor(student)).thenReturn(grades(8, 6, 10));
       double averageGrades = new GradesService(gradebook).averageGrades(student);
       assertThat(averageGrades).isEqualTo(8.0);
   }
}

Mock:模拟真实对象进行业务逻辑

当我们并不希望真的调用生产环境下的代码或者在测试中难于验证真实代码执行效果的时候,我们会用 Mock 来替代那些真实的对象。

如:
对邮件发送服务的测试,我们并不希望每次进行测试的时候都发送一封邮件,毕竟我们很难去验证邮件是否真的被发出了或者被接收了。

Mock 与 Stubs的区分?

Stub和Mock的区别在于,Stub偏向于结果验证,Mock则更加偏向于行为验证。通俗来说,stub是针对真实数据,而Mock是模拟数据.
虽然Mock和Stub本质上是不同的,但是随着各种Mock框架的引入,Stub和Mock的边界越来越模糊,使得Mock不仅可以进行行为验证,同样也具备Stub对接口的假实现的能力.

无效单元测试

  1. 启动Spring容器
  2. 连接数据库

有效单元测试

  1. 业务逻辑层Service需要重点测试
  2. 自定义工具类,正则表达式等固定逻辑

扩展

  1. java - 阿里等大厂的研发流程,进去前先了解一下_个人文章 - SegmentFault 思否
  2. Test Doubles - Fakes, Mocks and Stubs.
  3. GitHub - yangyubo/zh-unit-testing-guidelines: Geotechnical 单元测试准则 - 中文版
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值