0

我正在尝试使用 rspec 对一些 ruby​​ 代码执行突变测试。我只是在学习红宝石,我真的不知道我是否做得对。我要测试的部分代码是:

class Cipher

 def initialize()
  @a_offset = 65 #'A'.unpack('C').first
  @z_offset = 90 #'Z'.unpack('C').first
 end

 def encode(key, plain_text)
  key_offset = key.upcase.unpack('C').first

  cipher_text = plain_text.upcase.split('').collect do |letter| 
   cipher_letter = (letter.unpack('C').first + key_offset - @a_offset)
   if cipher_letter > @z_offset
    cipher_letter -= ( @z_offset - @a_offset + 1 )
   end
   cipher_letter.chr
 end

 return cipher_text.join
end

到目前为止,我的测试套件如下所示:

require 'rspec'
require 'Cipher'

describe "#initialize" do 
   it "should have correct @a_offset" do
     encoder = Cipher.new()
     expect(encoder.instance_variable_get(:@a_offset)).to eq 65
   end 

   it "should have correct @z_offset" do
     encoder = Cipher.new()
     expect(encoder.instance_variable_get(:@z_offset)).to eq 90
   end
 end 

describe "#encode" do
   it "It should correctly encode Caesar with key = A"do
     encoder = Cipher.new()
     expect(encoder.encode('R', 'CAESAR')).to eq ("TRVJRI")
   end 
end

运行 rspec 时,我的 3 个测试通过了。但是,当我在这个套件上使用突变测试时,我只杀死了 3/343,这不是很好。

4

1 回答 1

0

由于您的目标是开发足够突变的测试套件,因此未杀死的突变基本上为测试内容提供了指导。理想情况下,您的问题应该为生成的突变体提供一些示例,这些突变体不会被您的测试套件杀死,以便其他人可以评论如何编写杀死它们的测试。

让我尝试通过一般性建议和示例来最好地回答您的问题。我不熟悉您使用的特定突变测试工具,但通常您应该遵循类似于以下的过程*:

  1. 选择一个未被您的测试套件杀死的突变体并确定它是否可以被杀死(突变体可能在语义上等同于您的程序 - 如果是,则将其从突变体池中丢弃)。

  2. 编写一个杀死所选突变体的测试——也就是说,编写一个通过你的原始程序但在突变体上失败的测试。

    • 确定触发由突变体引入的错误行为的合适输入。
    • 确定一个合适的测试 oracle 断言您的程序的预期行为/输出(即,通过您的原始程序但在突变体上失败的测试 oracle)。

请记住,您的目标应该是编写简单地杀死所有突变体的最小测试,而是编写在您的项目上下文中有意义并且作为副产品杀死突变体的测试。同样,如果您可以为您的测试套件不会杀死的突变体提供一些具体示例,我和其他人可以更好地评论缺少哪些测试。

示例:假设您有一个突变体,它引入了以下错误(即,更改了原始程序的 if 语句中的关系运算符): - if cipher_letter > @z_offset + if cipher_letter >= @z_offset 杀死这个突变体需要一个检查边界条件的测试——也就是说,一个编码的测试'Z' 至少有一个字符。您当前的测试套件没有这样的测试。

*此过程描述了传统的突变测试。最近的研究[1] , [2]表明 (1) 并非所有可杀死的突变体都应该被杀死(一些突变体引发的测试根本没有意义)和 (2) 等效的突变体可能表明您的程序中存在问题(例如,不需要的冗余或歧义),您可能想要修复而不是丢弃等效的突变体。

于 2018-10-05T14:49:28.067 回答