我有一个方法可以对Cat模型执行一些操作,如果输入错误会引发异常:
context "hungry cat" do
it { expect { eat(what: nil) }.to raise_error }
end
我想要做的是检查这种方法是否会改变猫的状态,如:
context "hungry cat" do
it { expect { eat(what: nil) }.to raise_error }
it { expect { eat(what: nil) }.not_to change(cat, :status) }
end
问题是,由于eat(what: nil)
会引发异常,所以第二个it
无论如何都会失败。那么,是否可以忽略异常并检查某些条件?
我知道可以这样做:
it do
expect do
begin
eat(what: nil)
rescue
end
end.not_to change(cat, :status)
end
但这太丑了。
答案 0 :(得分:21)
您可以使用and
chain肯定断言。如果你想在链中混合一个否定的,RSpec 3.1引入了define_negated_matcher
。
您可以执行以下操作:
RSpec::Matchers.define_negated_matcher :avoid_changing, :change
expect { eat(what: nil) }
.to raise_error
.and avoid_changing(cat, :status)
受this comment的启发。
答案 1 :(得分:19)
您可以使用“救援无效”成语缩短您已有的内容:
it { expect { eat(what: nil) rescue nil }.not_to change(cat, :status) }
答案 2 :(得分:12)
在RSpec 3中,您可以将两个测试链接成一个。我发现这比rescue nil
方法更具可读性。
it { expect { eat(what: nil) }.to raise_error.and not_to change(cat, :status)}
答案 3 :(得分:0)
奇怪的是,eat(what: nil)
代码并不是针对每个测试单独运行的,而是影响其他测试。我不确定,但也许稍微重新编写测试可以解决问题或更准确地确定问题所在(在下面选择你的风味)。
使用should
:
context "hungry cat" do
context "when not given anything to eat" do
subject { -> { eat(what: nil) } }
it { should raise_error }
it { should_not change(cat, :status) }
end
end
使用expect
:
context "hungry cat" do
context "when not given anything to eat" do
let(:eating_nothing) { -> { eat(what: nil) } }
it "raises an error" do
expect(eating_nothing).to raise_error
end
it "doesn't change cat's status" do
expect(eating_nothing).to_not change(cat, :status)
end
end
end
答案 4 :(得分:0)
您还可以将期望值放入期望值块中。它仍然是一个小丑陋的地方,但是应该可以工作:
expect do
# including the error class is just good practice
expect { cat.eat(what: nil) }.to raise_error(ErrorClass)
end.not_to change { cat.status }