如何在Rails / RSpec中测试异常引发?


84

有以下代码:

def index
    @car_types = car_brand.car_types
end

def car_brand
    CarBrand.find(params[:car_brand_id])
    rescue ActiveRecord::RecordNotFound
        raise Errors::CarBrandNotFound.new 
end

我想通过RSpec对其进行测试。我的代码是:

it 'raises CarBrandNotFound exception' do
    get :index, car_brand_id: 0
    expect(response).to raise_error(Errors::CarBrandNotFound)
end

ID等于0的CarBrand不存在,因此我的控制器代码引发了Errors :: CarBrandNotFound,但是我的测试代码告诉我什么都没有提出。我该如何解决?我怎么了

Answers:


115

为了规范错误处理,需要在一个块上设置您的期望。评估对象不会引发错误。

所以你想做这样的事情:

expect {
  get :index, car_brand_id: 0
}.to raise_error(Errors::CarBrandNotFound)

有关详细信息,请参见期望错误

不过,我对您没有遇到任何冒泡的现象感到有些惊讶,直到达到规格结果。


1
@ jakob-s您在此处使用的预期错误行为不适用于控制器请求。该get :index, car_brand_id: 0本身不会引发错误。
里卡多·奥特罗

@RicardoOtero事情可能已经改变,但是对于我来说,它的价值是:gist.github.com/koppen/0e1d0894a908a3768847。但是可以肯定的是,堆栈中的某些内容可能会在错误传给规范运行程序之前处理该错误。
Jakob S

对于当前的rspec版本,这是正确的答案,应该予以表决
尼尔·伍兹

那是正确的。测试异常的正确形式是在除外方法上使用{}代替()。
Luiz Henrique

109

使用expect{}代替expect()


7
值得指出的是,这可以解决问题,因为{}语法创建了一个块来监视要引发的给定异常。在检查代码块引发异常时,MiniTest具有类似的语法要求。
阿古斯

1
这么小的变化。我让我的车轮磨了一会儿。谢谢你
josh

4
我不敢相信 1小时的尝试,它变成( ){ }!谢谢你这么多
西蒙弗伦岑

1
是的,对我来说也是一样-我相信我会花更多的

2
我知道我应该使用评论来询问...但是,我仍然要感谢您的答复。经过多种方法,最终我找到了解决问题的方法。
Florin Lei

18

get :index 永远不会引发异常-而是像真实服务器那样将响应设置为500错误。

而是尝试:

it 'raises CarBrandNotFound exception' do
  controller.params[:car_brand_id] = 0
  expect{ controller.car_brand }.to raise_error(Errors::CarBrandNotFound)
end

1
我很高兴有人提到这个!:)雅各布(Jakob)试图教育他们,在提出最高建议的答案中永远不会提出例外,但他面临一些不正确的抵制。👍
塔里克N. Elsamni
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.