如何使用 RSpec 测试在控制器方法中调用了 class
How to test that a class is called in a controller method with RSpec
我正在测试我的控制器以确保库 class 被调用并且功能按预期工作。 注意:这可能在其他地方被问过,但我需要帮助解决我的具体问题。我也很想知道如何最好地对此进行测试。
为了更好地解释我的问题,我将通过代码提供上下文。
我的 /Lib
文件夹中有一个 class 可以发出事件(如果您不明白那是什么意思,请不要介意)。 class 看起来像这样:
class ChangeEmitter < Emitter
def initialize(user, role, ...)
@role = role
@user = user
...
end
def emit(type)
case type
when CREATE
payload = "some payload"
when UPDATE
payload = "some payload"
...
end
send_event(payload, current_user, ...)
end
end
以下是我在我的控制器中使用它的方式:
class UsersController < ApplicationController
def create
@user = User.new(user_params[:user])
if @user.save
render :json => {:success => true, ...}
else
render :json => {:success => false, ...}
end
ChangeEmitter.new(@user, @user.role, ...).emit(ENUMS::CREATE)
end
end
抱歉,如果某些代码没有意义,我试图在不暴露太多代码的情况下解释问题。
以下是我为测试所做的尝试:
describe UsersController do
before { set_up_authentication }
describe 'POST #create' do
it "calls the emitter" do
user_params = FactoryGirl.attributes_for(:user)
post :create, user: user_params
expect(response.status).to eq(200)
// Here is the test for the emitter
expect(ChangeEmitter).to receive(:new)
end
end
end
我希望 ChangeEmitter
class 收到 new
因为创建操作会立即调用它。
相反,这是我得到的错误:
(ChangeEmitter (class)).new(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
我在上面的代码中遗漏了什么,为什么 class 没有收到新的。有没有更好的方法来测试上述功能?请注意,这是 Rspec。非常感谢您的帮助。谢谢。
您需要将 expect(ChangeEmitter).to receive(:new)
代码放在 post 请求之上。当您期望 class 接收方法时,您的 "expect" 语句在调用控制器之前执行。它期待将来会发生一些事情。所以你的测试应该看起来像:
it "calls the emitter" do
user_params = FactoryGirl.attributes_for(:user)
expect(ChangeEmitter).to receive(:new)
post :create, user: user_params
expect(response.status).to eq(200)
end
编辑
注意到您在调用 "new" 后链接了 "emit" 操作后,我意识到我需要针对您的特定用例更新我的答案。您需要 return 一个可以调用 emit 的对象(我通常 return 间谍或替身)。有关间谍和替身之间区别的更多信息,请查看:
https://www.ombulabs.com/blog/rspec/ruby/spy-vs-double-vs-instance-double.html
基本上,间谍会接受调用它的任何方法和 return 本身,而对于双精度,您必须指定它可以接受哪些方法以及 returned 是什么。对于你的情况,我认为间谍有效。
所以你想这样做:
it "calls the emitter" do
user_params = FactoryGirl.attributes_for(:user)
emitter = spy(ChangeEmitter)
expect(ChangeEmitter).to receive(:new).and_return(emitter)
post :create, user: user_params
expect(response.status).to eq(200)
end
我正在测试我的控制器以确保库 class 被调用并且功能按预期工作。 注意:这可能在其他地方被问过,但我需要帮助解决我的具体问题。我也很想知道如何最好地对此进行测试。
为了更好地解释我的问题,我将通过代码提供上下文。
我的 /Lib
文件夹中有一个 class 可以发出事件(如果您不明白那是什么意思,请不要介意)。 class 看起来像这样:
class ChangeEmitter < Emitter
def initialize(user, role, ...)
@role = role
@user = user
...
end
def emit(type)
case type
when CREATE
payload = "some payload"
when UPDATE
payload = "some payload"
...
end
send_event(payload, current_user, ...)
end
end
以下是我在我的控制器中使用它的方式:
class UsersController < ApplicationController
def create
@user = User.new(user_params[:user])
if @user.save
render :json => {:success => true, ...}
else
render :json => {:success => false, ...}
end
ChangeEmitter.new(@user, @user.role, ...).emit(ENUMS::CREATE)
end
end
抱歉,如果某些代码没有意义,我试图在不暴露太多代码的情况下解释问题。
以下是我为测试所做的尝试:
describe UsersController do
before { set_up_authentication }
describe 'POST #create' do
it "calls the emitter" do
user_params = FactoryGirl.attributes_for(:user)
post :create, user: user_params
expect(response.status).to eq(200)
// Here is the test for the emitter
expect(ChangeEmitter).to receive(:new)
end
end
end
我希望 ChangeEmitter
class 收到 new
因为创建操作会立即调用它。
相反,这是我得到的错误:
(ChangeEmitter (class)).new(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
我在上面的代码中遗漏了什么,为什么 class 没有收到新的。有没有更好的方法来测试上述功能?请注意,这是 Rspec。非常感谢您的帮助。谢谢。
您需要将 expect(ChangeEmitter).to receive(:new)
代码放在 post 请求之上。当您期望 class 接收方法时,您的 "expect" 语句在调用控制器之前执行。它期待将来会发生一些事情。所以你的测试应该看起来像:
it "calls the emitter" do
user_params = FactoryGirl.attributes_for(:user)
expect(ChangeEmitter).to receive(:new)
post :create, user: user_params
expect(response.status).to eq(200)
end
编辑
注意到您在调用 "new" 后链接了 "emit" 操作后,我意识到我需要针对您的特定用例更新我的答案。您需要 return 一个可以调用 emit 的对象(我通常 return 间谍或替身)。有关间谍和替身之间区别的更多信息,请查看: https://www.ombulabs.com/blog/rspec/ruby/spy-vs-double-vs-instance-double.html
基本上,间谍会接受调用它的任何方法和 return 本身,而对于双精度,您必须指定它可以接受哪些方法以及 returned 是什么。对于你的情况,我认为间谍有效。
所以你想这样做:
it "calls the emitter" do
user_params = FactoryGirl.attributes_for(:user)
emitter = spy(ChangeEmitter)
expect(ChangeEmitter).to receive(:new).and_return(emitter)
post :create, user: user_params
expect(response.status).to eq(200)
end