【问题标题】:Rails 6 controller test failure: expect(CreatesProject).to have_received(:new).with({name: "Runway", task_string: "start something:2"})Rails 6 控制器测试失败:expect(CreatesProject).to have_received(:new).with({name: "Runway", task_string: "start something:2"})
【发布时间】:2021-02-04 07:33:54
【问题描述】:

我正在尝试在 Rails 应用程序中运行控制器测试。

控制器代码

这是控制器测试的代码(/app/controllers/projects_controller.rb):

class ProjectsController < ApplicationController
  ## START: show
  def show
    @project = Project.find(params[:id])
    respond_to do |format|
      format.html {}
      format.js { render json: @project.as_json(root: true, include: :tasks) }
    end
  end
  ## END: show

  def new
    @project = Project.new
  end

  def index
    @projects = Project.all
  end

  ## START: create
  def create
    @workflow = CreatesProject.new(
      name: params[:project][:name],
      task_string: params[:project][:tasks])
    @workflow.create
    if @workflow.success?
      redirect_to projects_path
    else
      @project = @workflow.project
      render :new
    end
  end
  ## END: create
end

控制器测试

这是终端显示错误的测试(/spec/controllers/projects_controller_spec):

require "rails_helper"

RSpec.describe ProjectsController, type: :controller do

  describe "create" do
    it "calls the workflow with parameters" do
      workflow = instance_spy(CreatesProject, success?: true)
      allow(CreatesProject).to receive(:new).and_return(workflow)
      post :create,
        params: {project: {name: "Runway", tasks: "start something:2"}}
      expect(CreatesProject).to have_received(:new)
        .with({name: "Runway", task_string: "start something:2"})
    end

  end

end

在我为用户和角色添加更多测试之前,此测试运行良好。

我添加了更多测试

这是我遵循的说明:

  • 我将此添加到 Gemfile:gem 'devise'
  • config/environments/development.rb 中,添加了一些默认邮件选项config.action_mailer.default_url_options = { host: 'localhost:3000' }
  • 给 config.routes.rb 一个根路由——例如,通过将根添加到: “项目#index”。
  • app/views/layouts/application.html.erb 文件中添加了以下内容:
<!DOCTYPE html>
<html>
  <head>
    <title>Gatherer</title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track':
       'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>

    <%= javascript_pack_tag "projects" %>
  </head>

  <body>
  
  <p class="notice"><%= notice %></p>
  <p class="alert"><%= alert %></p>
  <%= yield %>

  </body>
</html>
  • 已将以下内容添加到app/models/user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
  • 已将以下内容添加到spec/support/devise.rb
RSpec.configure do |config|
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::ControllerHelpers, type: :view
config.include Devise::Test::IntegrationHelpers, type: :system
config.include Devise::Test::IntegrationHelpers, type: :request
end
  • 已将以下内容添加到test/test_helper.rb
module ActionController
  class TestCase
    include Devise::Test::ControllerHelpers
  end
end

module ActionDispatch
  class IntegrationTest
    include Devise::Test::IntegrationHelpers
  end
end
  • 将此测试添加到spec/system/user_and_role_spec.rb
require "rails_helper"

RSpec.describe "with users and roles" do

    def log_in_as(user)
        visit new_user_session_path
        fill_in("user_email", with: user.email)
        fill_in("user_password", with: user.password)
        click_button("Log in")
    end

    let(:user) { User.create(email: "test@example.com", password: "password") }

    it "allows a logged-in user to view the project index page" do
        log_in_as(user)
        visit(projects_path)
        expect(current_path).to eq(projects_path)
    end

    it "does not allow a user to see the project page if not logged in" do
        visit(projects_path)
        expect(current_path).to eq(user_session_path)
    end

end
  • 为了使测试通过,我将其添加到app/controllers/application_controller.rb
module ActionController
  class TestCase
    include Devise::Test::ControllerHelpers
  end
end

module ActionDispatch
  class IntegrationTest
    include Devise::Test::IntegrationHelpers
  end
end
  • 这是app/controllers/application_contoller.rb 文件:
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  before_action :authenticate_user!
end

错误

运行命令bundle exec rspec后,出现以下错误:

1) ProjectsController create calls the workflow with parameters
     Failure/Error:
       expect(CreatesProject).to have_received(:new)
         .with({name: "Runway", task_string: "start something:2"})
     
       (CreatesProject (class)).new({:name=>"Runway", :task_string=>"start something:2"})
           expected: 1 time with arguments: ({:name=>"Runway", :task_string=>"start something:2"})
           received: 0 times
     # ./spec/controllers/projects_controller_spec.rb:11:in `block (3 levels) in <top (required)>'

谁能帮我解决这个问题?

【问题讨论】:

  • 到目前为止,您尝试了哪些调试方法?
  • @Kielstra 你能指导我如何调试代码吗?我是新手。如果你能帮助我,那就太好了。
  • 你的代码没有问题,测试用例是完美的,也是控制器,请分享你的路线,你的其他测试都是绿色的吗?
  • @KamalPanhwar 我也添加了一些其他测试,因为它们我开始收到此错误。我也应该共享这些文件吗?
  • 确定你可以分享我可以检查他们,以上都是正确的。

标签: ruby-on-rails rspec controller rspec-rails ruby-on-rails-6


【解决方案1】:

当您添加身份验证代码时,这意味着现在您的所有控件都需要用户登录。确保您拥有 spec/support/devise.rb 文件,其中包含以下内容n

RSpec.configure do |config|
  config.include Devise::Test::ControllerHelpers, type: :controller
  config.include Devise::Test::ControllerHelpers, type: :view
  config.include Devise::Test::IntegrationHelpers, type: :system
  config.include Devise::Test::IntegrationHelpers, type: :request
end

现在在您的测试用例中添加两行用于创建user,另一行用于登录用户,现在您完成测试spec/controllers/projects_controller_spec.rb 将具有以下内容

require 'rails_helper'

RSpec.describe ProjectsController, type: :controller do
  describe 'create' do
    let(:user) { User.create(email: 'test@example.com', password: 'password') }
    it 'calls the workflow with parameters' do
      sign_in(user)
      workflow = instance_spy(CreatesProject, success?: true)
      allow(CreatesProject).to receive(:new).and_return(workflow)
      post :create,
      params: { project: { name: "Runway", tasks: "start something:2" } }
      expect(CreatesProject).to have_received(:new)
        .with(name: 'Runway', task_string: 'start something:2')
    end
  end
end

注意:第 13 章:安全性测试解释了这方面的所有内容,甚至通过将项目与角色和用户绑定更进一步,所以你应该阅读它两次以理解所有这些以及为什么它会给出你的错误,随着你的深入需要为角色和工作流程添加更多更改。

【讨论】:

  • 仍然无法解决问题:(如果您需要更多文件,请告诉我。我面临这个问题已经有一段时间了,但不知道如何解决它:(
  • 好分享applciation_controller
  • 现在可以查一下吗?我已经分享了文件。
  • 所以我的回答中给出了您的 application_controller 问题解决方案,您需要尝试一下。 before_action :authenticate_user! 正在使您的控制器经过身份验证,但您的测试没有,因此您必须使用建议的解决方案来执行此操作。如果您想确定只需评论# before_action :authenticate_user! 行,您的测试就会通过。检查上面的解决方案你可能做错了什么。
  • 现在我得到了不同的错误:Failure/Error: expect(current_path).to eq(user_session_path) expected: "/users/sign_in" got: "/projects" (compared using ==)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-30
  • 1970-01-01
  • 2013-12-01
  • 1970-01-01
相关资源
最近更新 更多