递归函数的白盒和黑盒测试

时间:2018-03-15 14:45:21

标签: recursion f# black-box-testing white-box-testing

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

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

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

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

1 个答案:

答案 0 :(得分: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. 生成两个随机数,ab并检查gcd a b = gcd b a。这只是测试一个非常基本的属性,但它可以覆盖很多情况。

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