3

我在迭代函数方面学习了白盒和黑盒测试。现在我需要对几个递归函数(在 F# 中)进行白盒和黑盒测试。对 gcd 采用以下递归算法:

gcd (m, n)
    if  (m % n) = 0 then
         n
    else 
        gcd n ( m % n)

对于白盒测试:我究竟如何覆盖算法的不同分支?天真地可以说有两个分支,但是当函数被多次调用时,可能的分支显然会增加。我是否应该使用导致不同数量的递归调用的参数进行测试,或者我应该如何确定要测试的值?

黑盒:我了解黑盒测试的一般概念。我们应该在不了解其内部工作原理的情况下查看我们可能想要调用该函数的可能值。在这种情况下,我只是不确定我们可能想用哪些值来调用它。一种方法可能是从 gcd = 1 的两个值 m 和 n 开始,然后对值 m 和 gcd = 2 执行相同操作,直到某个任意数 n 的某个 gcd= n。这是应该如何去做的吗?

4

1 回答 1

3

首先,我认为对于如何对递归函数进行白盒和黑盒测试没有一个单一的既定定义,但这是我对它的解释。

白盒测试。我们想根据其内部工作来测试该功能。在递归函数的情况下,我认为这意味着我们想要测试它所做的递归调用是否是我们所期望的。一种方法是记录所有递归调用。一个简单的实现gcd就是添加一个参数来保存日志并返回结果:

let rec gcd log m n = 
  let log = (m, n)::log
  if (m % n) = 0 then List.rev log, n
  else gcd log n (m % n)

现在,对于某些两个参数,比如 54 和 22,您可以手动进行计算,确定递归调用的参数应该是什么并为此编写测试:

let log, res = gcd [] 54 22
log |> shouldEqual [ (54, 22); (22, 10); (10, 2) ]

黑盒测试。在这里,我们假设我们不知道该函数究竟是如何工作的,因此我们无法测试其内部结构。我们所能做的就是使用一些输入来测试它。考虑极端情况或棘手的输入可能是一个好主意,因为这些可能会导致问题。给定一个简单的实现:

let rec gcd m n = 
  if (m % n) = 0 then n
  else gcd n (m % n)

我可能会为以下内容编写测试:

// A random case where one of the numbers is the result
gcd 100 50 |> shouldEqual 50
gcd 50 100 |> shouldEqual 50

// A random case where the only divisor is 1
gcd 13 123 |> shouldEqual 1
gcd 123 13 |> shouldEqual 1

// The following are problematic and I'm not sure what the right behaviour is
gcd 0 0    // This probably should not be allowed    
gcd 10 -5  // This returns -5, but I'm not sure that's what we want

随机测试。 您还可以使用随机测试(这是一种黑盒测试)来自动生成多个测试用例。我能想到的至少有两个随机测试:

  1. 生成两个随机数,a然后b检查gcd a b = gcd b a. 这只是测试一个非常基本的属性,但它可以涵盖相当多的情况。

  2. 选择一个随机数a和几个素数p1, p2, ...。然后将素数分成两组并产生a*p1*p3*p5a*p2*p4*p6。编写一个测试,检查这两个数字的 GCD 是否为a

于 2018-03-15T15:48:01.303 回答