微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Rails 6 控制器测试失败: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"})

我正在尝试在 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>
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable,:lockable,:timeoutable and :omniauthable
devise :database_authenticatable,:registerable,:recoverable,:rememberable,:trackable,:validatable
end
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
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)>'

谁能帮我解决这个问题?

解决方法

当您添加身份验证代码时,这意味着现在您的所有控件都需要用户登录。请确保您拥有 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

现在在您的测试用例中添加两行,一行用于创建 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 章:安全性测试解释了关于此的所有内容,即使它通过将项目与角色和用户绑定来更进一步,因此您应该阅读两遍以了解所有这些以及为什么它会给出您的错误,随着您的深入需要为角色和工作流程添加更多更改。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。