我有一个算法可以在99%的置信度下工作。所以如果我设置这样的测试
let(:valid_input_signal) { randomly_generate_signal_plus_noise }
it { expect(my_detector(valid_input_signal).signal_present?).to be true }
它将失败1%的时间。我可以编写一个对数千个有效输入信号运行my_detector的测试,并检查它仅在1%的时间内失败,但这将花费很长时间,并且测试的目的不是检查算法是否有效,而是代码中没有任何改变算法的更改。
我认为实现此目的的有效方法是第二次运行上述测试,如果通过了,则给它通过。如果它第二次失败,则给它一次失败,因为假设基数正确,它连续两次失败的机会是10,000分之一。当然,这意味着在有效代码库中,每10,000倍的组合测试将失败,但这比目前的情况要好得多,后者在100倍的测试中失败。
那么rspec中是否有办法做到这一点,即如果第一次失败则第二次运行测试,而如果第二次失败则仅输出失败?
答案 0 :(得分:2)
,测试的目的不是检查算法是否有效,而是破坏算法的代码没有变化。
您无法在随机生成的输入数据中进行测试。假设您有一组100个valid_input_signals,但它在第5个失败,没关系。有人更改了算法,它从第5个开始通过,到第17个失败。在1%的情况下,它仍然会失败,但是仍然正确吗?
如何从此处继续尚不清楚-它取决于算法的作用。也许您可以将某些部分提取到单一职责组件中,并进行单独测试?
但是也许这是一个遗留算法,您需要尽可能多地用规格覆盖它吗?如果是这样-我会以覆盖速度为代价:
生成1000个信号,并将my_detector(valid_input_signal).signal_present? == true
的信号保存,保存在文件或其他内容中,并针对确定的输入运行规范。
valid_inputs.each do |input|
expect(my_detector(input).signal_present?).to be true
end
让我们说其中的10个给出false
,检查并确认这是一个真实的否定项(假定返回false),将它们保存在其他位置并为其指定规格:>
invalid_inputs.each do |input|
expect(my_detector(input).signal_present?).to be false
end
让我们说(经过手动检查),其中只有8个为真阴性,剩下的2个应该返回true,但返回false-这些可能是错误。保存以备后用。
您对1000个样本的覆盖范围满意吗?跑步需要多长时间?您可以在这段时间内进行交易并将覆盖率增加到10000个样本吗?百万?这是你的选择。
在某些时候添加更多样本毫无意义。现在,您已经大致了解了整个算法,并且可以开始一些基本的重构,例如extract method或name magic constants并提取逻辑组件(在此答案的第2部分中提到)。 X样本测试是临时的,它们确保(尽可能多地使用非无限样本大小),当您删除一部分您更了解的算法时,整个算法的行为不会改变。
答案 1 :(得分:1)
尝试一下:
describe '#my_decorator' do
let(:valid_input_signal_1) { randomly_generate_signal_plus_noise }
let(:valid_input_signal_2) { randomly_generate_signal_plus_noise }
it 'should not fail twice in a row' do
fail unless my_detector(valid_input_signal_1).signal_present? || my_detector(valid_input_signal_2).signal_present?
end
end