初探-契约测试(Contract Test)

—题记:人们总是好奇什么是永恒的,然而唯有变化是永恒的

自打一进入公司以来,就体验到了测试的重要性

无论是TDD、Bug bush、Unit test、Integration test、E2E Test…

都不禁让我感受世界之浩瀚,测海之无涯

所以,随着新项目上需要认识一个Contract Test的东西之后

我不禁感慨道,还有完没完了?😂

测试金字塔

在了解契约测试之前,不得不先祭出经典的测试金字塔

从图上可以很清楚的看到,金字塔越往上反馈的时间越长,同时花费的代价也越大

  • 所以平时我们更多的精力是放在Unit Test中,方便更及时的发现潜在的风险,还能降低成本

  • Integration Test则往往需要启动mock server,所以开销相对会更大一些。
    但同时,相对于Unit Test它更加不关注细节,测试的范围更广

曾经有一个项目写了非常多的Integration Test,导致每次push代码的时候,都要跑8分钟的测试

  • E2E Test和更高等级的测试更加贴近用户操作,所以对于软件内部细节则越来越不关注。

虽然金字塔尖的测试成本高昂,但是也是必须要做的。因为这些测试更加贴近用户操作,容易发现之前测试考虑不到的地方。同时这也是产品上线前的最后一次发现问题的机会。

看到这里,想必上面的各种测试已经将软件的方方面面都测试完了,那还需要什么契约测试吗?

在回答这个问题前,我们不妨先想一想

即当今天下,微服务遍地走,外部服务多如狗的时代

如果要跨Service 或者 集成第三方服务的时候上面的测试还能不能hold住?(思考2秒…..)

答案当然是否定的。否则我接下来讲什么

那么,什么是契约测试?

此时,契约测试就横空出世了

什么是契约(Contract)?Wikipedia上有一段解释

A contract is an agreement that specifies certain legally enforceable rights and obligations pertaining to two or more mutually agreeing parties.

说人话就是,双方约定好的12345写在纸上,然后拉勾上吊一百年不许变~

设想一下,当我们的软件要和第三方交互的时候,如果没有一个约定好的数据格式。那今天我们按照别的服务设计的数据格式,明天他改了,我们就只能重做,这显然是不利于我们开发的。

这里简单的以ProviderConsumer来举例。

往往一个Provider 对应多个Consumer,而Provider 虽然叫生产者,但是他的价值是由下游的Consumer来决定的。所以契约是由Consumer生成的,并要求Provider 按照需求提供数据。

摘自Pact官网上的描述:Pact is a code-first consumer-driven contract testing tool, and is generally used by developers and testers who code. The contract is generated during the execution of the automated consumer tests.

一旦契约建立,ProviderConsumer则使用该套契约进行各自的测试

例如我们这里的Provider 是一家天气预报服务商,两个Consumer_A Consumer_B分别消费不同的数据结构体

如果Consumer_B希望提供更加详细的Area位置,并且Provider 考虑改需求后修改了Area的数据结构,例如

1
2
3
4
"Area":{
"City":"Cheng du"
"District":"tian fu xin qu"
}

那么,显然Consumer_A就崩溃了

此时,Consumer_A的契约测试就会挂掉,属于典型的契约破坏,至于之后要怎么修改,那就是Consumer_AProvider 俩个团队协商了

总体的过程如下所示:

契约测试展示图

参考例子(Pact)

由于篇幅关系,本文不具体写代码示例(也许之后会单独写一个)
感兴趣的读者可以参考这个项目 -> pact-example

特别注意的是

  1. 契约测试是由Consumer驱动的,意味着契约只约束了Consumer要求的部分,其余的Provider 提供的数据不受契约测试的保护
  2. 老马的意思是,契约测试不需要在构建pipeline中运行,每天跑一次就够了

参考文献

[1] Contract Testing Vs Integration Testing
[2] ContractTest
[3] PACT