本港台开奖现场直播 j2开奖直播报码现场
当前位置: 新闻频道 > IT新闻 >

wzatv:【j2开奖】改善单元测试的新方法

时间:2016-11-18 19:59来源:香港现场开奖 作者:118开奖 点击:
我们为什么要写单元测试? 满足需求是所有软件存在的必要条件,单元测试一定是为它服务的。从这一点出发,我们可以总结出写单元测试的两个动机: 驱动(如:TDD)和验证功能实

wzatv:【j2开奖】改善单元测试的新方法

  我们为什么要写单元测试

  "满足需求"是所有软件存在的必要条件,单元测试一定是为它服务的。从这一点出发,我们可以总结出写单元测试的两个动机:驱动(如:TDD)和验证功能实现。另外,软件需求“易变”的特征决定了修改代成为必然,在这种情况下,单元测试能保护已有的功能不被破坏。

  基于以上两点共识,我们看看传统的单元测试有什么特征?基于用例的测试(By Example)

  单元测试最常见的套路就是Given、When、Then三部曲。

Given:初始状态或前置条件

When:行为发生

Then:断言结果

  编写时,我们会精心准备(Given)一组输入数据,然后在调用行为后,断言返回的结果与预期相符。这种基于用例的测试方式在开发(包括TDD)过程中十分好用。因为它清晰地定义了输入输出,而且大部分情况下体量都很小、容易理解。

  但这样的测试方式也有坏处。

第一点在于测试的意图。用例太过具体,我们就很容易忽略自己的测试意图。比如我曾经看过有人在写计算器kata程序的时候,将其中的一个测试命名为“return 3 when add 1 and 2”,这样的命名其实掩盖了测试用例背后的真实意图——传入两个整型参数,调用add方法之后得到的结果应该是两者之和。我们常说测试即文档,既然是文档就应该明确描述待测方法的行为,而不是陈述一个例子。

第二点在于测试完备性。因为省事省心并且回报率高,我们更乐于写happy path的代尽管出于职业道德,我们也会找一个明显的异常路径进行测试,不过这还远远不够。

  

wzatv:【j2开奖】改善单元测试的新方法

  为了辅助单元测试改善这两点。我这里介绍另一种测试方式——生成式测试(Generative Testing,也称Property-Based Testing)。这种测试方式会基于输入假设输出,并且生成许多可能的数据来验证假设的正确性。

  生成式测试

  对于第一个问题,我们换种思路思考一下。假设我们不写具体的测试用例,而是直接描述意图,那么问题也就迎刃而解了。想法很美好,但如何实践Given、When、Then呢?答案是让程序自动生成入参并验证结果。这也就引出“生成式测试”的概念——我们先声明传入数据可能的情况,然后使用生成器生成符合入参情况的数据,调用待测方法,最后进行验证。

  Given阶段

  Clojure 1.9(Alpha)新内置的Clojure.spec可以很轻松地做到这点:

  ;; 定义输入参数的可能情况:两个整型参数 (s/def ::add-operators (s/cat :a int? :b int?)) ;; 尝试生成数据 (gen/generate (s/gen ::add-operators)) ;; 生成的数据 -> (1 -122)

  首先,我们尝试声明两个参数可能出现的情况或者称为规格(specification),即参数a和b都是整数。然后调用生成器产生一对整数。整个分析和构造的过程中,都没有涉及具体的数据,这样会强制我们揣摩输入数据可能的模样,而且也能避免测试意图被掩盖掉——正如前面所说,return 3 when add 1 and 2并不代表什么,return the sum of two integers才具有普遍意义。

  Then阶段

  数据是生成了,待测方法也可以调用,但是Then这个断言阶段又让人头疼了,因为我们根本没法预知生成的数据,也就无法知道正确的结果,怎么断言?

  拿定义好的加法运算为例:

  (defn add [a b] (+ a b))

  我们尝试把断言改成一个全称命题: 任取两个整数a、b,a和b加起来的结果总是a、b之和。 借助test.check,我们在Clojure可以这样表达:

  (def test-add (prop/for-all [a (gen/int) b (gen/int)] (= (add a b) (+ a b))))

  不过,我们把add方法的实现(+ a b)写到了断言里,这几乎丧失了单元测试的基本意义。换一种断言方式,我们使用加法的逆运算进行描述: 任取两个整数,把a和b加起来的结果减去a总会得到b。

  (def test-add (prop/for-all [a (gen/int) b (gen/int)] (= (- (add a b) a) b))))

  我们通过程序陈述了一个已知的真命题。变换以后,就可以使用quick-check对多组生成的整数进行测试。

  ;; 随机生成100组数据测试add方法 (tc/quick-check 100 test-add) ;; 测试结果 -> {:result true, :num-tests 100, :seed 1477285296502}

  测试结果表明,刚才运行了100组测试,并且都通过了。理论上,程序可以生成无数的测试数据来验证add方法的正确性。即便不能穷尽,我们也获得一组统计上的数字,而不仅仅是几个纯手工挑选的用例。

(责任编辑:本港台直播)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
栏目列表
推荐内容