简体   繁体   English

RSpec没有加载ControllerMacros方法

[英]ControllerMacros method not being loaded by RSpec

I've added a ControllerMacro but the method isn't being made available in my specs. 我添加了一个ControllerMacro但我的规格中没有提供该方法。 My specs will fail with: 我的规格将失败:

NoMethodError: undefined method `attributes_with_foreign_keys' for FactoryGirl:Module

I'm trying to do this following this discussion on Github. 我正在尝试在Github上讨论之后这样做。 I've looked at other similar questions but most point at using config.include ControllerMacros, :type => :controller instead of config.extend ControllerMacros, :type => :controller which I'm doing already. 我看过其他类似的问题,但大多数都指向使用config.include ControllerMacros, :type => :controller而不是config.extend ControllerMacros, :type => :controller我已经在做了。

Now I know that the controller_macros.rb file is being loaded upon starting the test as I've run the specs through RubyMine's debugger but why the method isn't available is beyond me! 现在我知道在启动测试时正在加载controller_macros.rb文件,因为我通过RubyMine的调试器运行规范,但为什么这个方法不可用超出了我!

spec_helper.rb

require 'simplecov'
SimpleCov.start 'rails'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'email_spec'
require 'rspec/autorun'

Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

RSpec.configure do |config|
  config.include(EmailSpec::Helpers)
  config.include(EmailSpec::Matchers)
  config.include ControllerMacros, :type => :controller

  config.include FactoryGirl::Syntax::Methods

  config.use_transactional_fixtures = true

  config.infer_base_class_for_anonymous_controllers = false

  config.order = "random"

  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
  end
  config.before(:each) do
    DatabaseCleaner.start
  end
  config.after(:each) do
    DatabaseCleaner.clean
  end
end

spec/support/macros/controller_macros.rb

module ControllerMacros
  def attributes_with_foreign_keys(*args)
    FactoryGirl.build(*args).attributes.delete_if do |k, v|
      ["id", "type", "created_at", "updated_at"].member?(k)
    end
  end
end

This example controller spec: 此示例控制器规范:

describe "POST create" do
  describe "with valid params" do
    it "creates a new Course" do
      expect {
        #post :create, course: FactoryGirl.build(:course)
        post :create, course: FactoryGirl.attributes_with_foreign_keys(:course)
      }.to change(Course, :count).by(1)
    end

The reason of failing: 失败的原因:

The macro you defined is a method within a module. 您定义的宏是模块中的方法。 You asked Rspec to include the module, so the method is available to Rspec's instance, which should be used similar to describe , it etc. 您要求Rspec包含该模块,因此该方法可用于Rspec的实例,该实例应与describeit等类似。

However, you used this method as a FactoryGirl's class method. 但是,您将此方法用作FactoryGirl的类方法。 Obviously this is not working. 显然这不起作用。

The solution. 解决方案。

It looks you want to have a convenient method to quickly build a set of pre-defined attributes of a model in a special case. 在特殊情况下,您希望有一种方便的方法来快速构建模型的一组预定义属性。

This logic is better not to be a "macro", because it's better to use FactoryGirl as a centralized place to store all logic about models. 这种逻辑最好不要成为“宏”,因为最好将FactoryGirl用作存储模型所有逻辑的集中位置。

So, the most convenient way is, beyond your normal factories, define a special factory for this case, say foo , with all association and other logic you need inside it, and inherit from other normal factory. 因此,最方便的方法是,除了正常的工厂之外,为这种情况定义一个特殊的工厂,比如foo ,它包含你需要的所有关联和其他逻辑,并从其他正常工厂继承。

If it's name is foo , then you can easily build a hash of foo's attributes like FactoryGirl.attributes_for :foo 如果它的名字是foo ,那么你可以轻松地建立一个foo的属性的散列,如FactoryGirl.attributes_for :foo

Instead of calling: 而不是打电话:

post :create, course: FactoryGirl.attributes_with_foreign_keys(:course)

Just call: 只需致电:

post :create, course: attributes_with_foreign_keys(:course)

Took advice from @Billy Chan answer. 从@Billy Chan的回答中得到建议。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM