相同的rspec测试分别成功和失败

时间:2013-11-19 05:33:01

标签: ruby rspec

我正在编写一个简单的程序,将汇编语言指令转换为我们正在构建的处理器的各自24位二进制指令。我在Ruby(2.0.0)中编写程序并使用Rspec(2.14.6)对其进行测试。奇怪的是,我可以运行两个相同的测试 - 其中一个失败,另一个失败。这是一个例子:

测试失败:

it "Returns 24-bit binary instruction for valid line of assembly code" do

  #...25 other instructions are tested before these...
  expect(Parser.build_instruction("Li r2, 0000111001010001")).to eq("001000001110010100010010")
  expect(Parser.build_instruction("Li r2, 0000111001010001")).to eq("001000001110010100010010")

end

通过测试:

it "Returns 24-bit binary instruction for valid line of assembly code" do

  #...25 other instructions are tested before these...
  expect(Parser.build_instruction("Li r2, 0000111001010001")).to eq("001000001110010100010010")
  #expect(Parser.build_instruction("Li r2, 0000111001010001")).to eq("001000001110010100010010")

end

我开始怀疑你是否可以在一个it...do...end块中进行太多测试(或者如果两次运行相同的expect是个问题),但我尝试复制一些测试在这最后两个之上,测试继续通过。我还尝试将一些测试拉出到他们自己的it...do...end块中,然后导致不同的期望(之前通过)失败。我有点困惑。想法?


P.S。我实际上并不想两次运行相同的expect,但是在下面的两个测试中它做了一些奇怪的事情,所以我改变了第二个测试以匹配第一个测试,但它仍然失败了。另外,如果我注释掉第一个测试(这两个),第二个测试通过。换句话说,如果我同时运行两个测试,它只会失败。

it "Returns 24-bit binary instruction for valid line of assembly code" do

  #...25 other instructions are tested before these...
  expect(Parser.build_instruction("Li r2, 0000111001010001")).to eq("001000001110010100010010")
  expect(Parser.build_instruction("Li r2, 111001010001")).to eq("001000001110010100010010")

end

输出:

1) Parser Returns 24-bit binary instruction for valid line of assembly code
 Failure/Error: expect(Parser.build_instruction("Li r2, 111001010001")).to eq("001000001110010100010010")

   expected: "001000001110010100010010"
        got: "0010000011100101000100001110010100010010"

   (compared using ==)
 # ./spec/parser_spec.rb:65:in `block (2 levels) in <top (required)>'

编辑1

@micahbf和@felix,我有一个方法,它接受一个输入文件,每行都有一条指令,用于转换为二进制代码。我只是在一个输入文件上运行它,Li r2, 111001010001重复约50次(我之前应该做的事:/),只有第一个输出是正确的 - 后续行添加1110010100010010到最后...

001000001110010100010010
0010000011100101000100001110010100010010
00100000111001010001000011100101000100001110010100010010
etc..

所以...这不是rspec;)我将不得不深入挖掘我的代码以找出粘贴的位置。


编辑2

对于那些希望知道的人(我愿意),在我的代码中,我找到了一个我必须返回对象的引用而不是值的位置。这导致原始对象被修改(我的头部受伤并且测试失败!):

def self.get_reg_code reg
    @logger.debug { "Getting register code for [ #{reg.inspect} ]" }
    reg.upcase!
    if register? reg
      return CODES["#{reg}".to_sym] # <-- Returning object reference!
    else
      return reg
    end
end

我把它更改为:

def self.get_reg_code reg
    @logger.debug { "Getting register code for [ #{reg.inspect} ]" }
    reg.upcase!
    if register? reg
      reg_code = CODES["#{reg}".to_sym].clone # <-- Return a copy--not the referenced object!
      return reg_code
    else
      return reg
    end
end

2 个答案:

答案 0 :(得分:1)

抱歉,看起来好像 rspec是正确的,而Parser错误。 :)

特别考虑到它失败的原因(“0010000011100101000100001110010100010010”),它看起来好像Parser有一些存储指令的状态。

要测试这个假设,请第三次运行代码(但第二次没有预料到)。如果失败则为“001000001110010100010000111001010001001000100001110010100010010”,则收集了我的状态假设的参数。

另一种“测试”方法是为每次调用build_instructions创建一个新的解析器实例。不是要实际规避这个问题,而是要对其进行调查。

你也可能需要像

这样的东西
describe "#build_instruction"
  it "resets state" do
    expect(Parser.build_instruction("Li r2, 0000111001010001")).to eq("001000001110010100010010")
    expect(Parser.build_instruction("Li r2, 111001010001")).to     eq("001000001110010100010010")
  end
end

您明确测试行为的地方。

答案 1 :(得分:0)

在测试之前拥有一个已知状态很重要。 因此,应该进行每次测试的设置和拆卸。 还有一个普遍的建议是“每次测试只有1个断言”。

基于此,我会继续将测试转移到自己的...结束块。你提到尝试这个但有一个问题,但没有显示问题。我会追求这条路。