【问题标题】:MyClass.inspect return incorrect class when I run whole test suite当我运行整个测试套件时,MyClass.inspect 返回不正确的类
【发布时间】:2017-04-09 15:13:18
【问题描述】:

当我运行整个测试套件时,MyClass.inspect 返回不正确的类。

问题:

我在项目中有 User::CreditCardActiveMerchant::Billing::CreditCard 课程。最后来自 activemerchant 宝石。 当我运行单一规格(rspec spec/models/user/credit_card_spec.rb)时,它可以正常工作。
当我运行整个套件(rspec spec)时,规范失败并显示undefined method...,没关系。 问题是,在这种情况下,我的CreditCard 课程不是我的!!!
当我运行单一规范并执行puts User::CreditCard.inpsect(或只是p User::CreditCard,或者只是User::CreditCard)时,它会按预期返回User::CreditCard当我运行整个套件并在规范中执行 p User::CreditCard 时,它会返回 ActiveMerchant::Billing::CreditCard


背景:

如果您不想阅读“背景”,请确保最后有 NOTE

我正在使用遗留代码。所以我并不完全了解图像的所有部分。

我想在我的用户中为信用卡创建Value Object。所以我创建了新的无表模型(注意路径和类名):

#app/models/user/credit_card.rb
class User::CreditCard
  include ActiveModel::Model

  delegate :card_number, :card_expiration, :card_type, to: :subscription

  def initialize(subscription)
    @subscription = subscription || Subscription.new
  end

  private

  attr_reader :subscription
end

当然我有用户模型:

#app/models/user.rb
class User
  ...
  has_one :subscription
  ...
  def credit_card
    @credit_card ||= User::CreditCard.new(subscription)
  end
end

我的用户/信用卡规格:

#spec/models/user/credit_card_spec.rb
require 'spec_helper'
# require 'user/credit_card' # if I include this then it works correct

RSpec.describe User::CreditCard, type: :model do
  let(:subscription) { build :subscription }
  let(:credit_card) do
    p User::CreditCard # this result depends on whole/not whole suite run...
    # rspec spec => ActiveMerchant::Billing::CreditCard
    # rspec spec/models/user => User::CreditCard
    User::CreditCard.new(subscription)
  end

  it 'should delegate alowed messages to user subscription' do
    %w[card_number card_expiration card_type].each do |attr|
      expect(credit_card.public_send(attr)).to eql subscription.public_send(attr)
    end
  end

  it 'disallow another methods' do
    expect { credit_card.unexisted_method }.to raise_error(NoMethodError)
  end
end

注意:

在规范中,我可以要求 'user/credit_card' 然后它会起作用。但是为什么没有它就不行呢? 会不会是其他地方的问题?例如在控制器或其他地方?

【问题讨论】:

  • @mudasobwa 我不确定这是否易于复制...
  • 无论如何,我猜问题根源在class User::CreditCard。 Rails 确实是巫毒自动加载,因为你有class User,所以User 是一个类或模块之间存在冲突。尝试将User::CreditCard 重命名为module UserDetails; class CredirCard。听起来很奇怪,但没有逻辑,也没有预测如何处理自动加载。
  • @mudasobwa …Minimal – Use as little code as possible that still produces the same problem - 我不确定它是否可以通过一小段代码来复制。 …Complete – Provide all parts needed to reproduce the problem - 我不确定我应该在complete 我的问题中添加什么...
  • 忘掉 MCVE,听起来就在这里。 Rails 的经验法则是:避免命名空间冲突,尤其是类和模块之间。
  • 太棒了!它有效:) 但对我来说很奇怪 %)

标签: ruby-on-rails ruby rspec activemerchant value-objects


【解决方案1】:

这是 rails 自动加载 + ruby​​ 常量分辨率的故障。

class C; end
CONST = 42
C::CONST
#⇒ (pry):3: warning: toplevel constant CONST referenced by C::CONST
#⇒ 42

令人惊讶的是,CONST 已解决。那是因为Ruby constant resolution algorithm

有两种方法可以解决这个问题:或者给类User::CreditCard 起一个不同的名称,或者确保它已被加载。否则,Rails 会在 ActiveMerchant::Billing 命名空间中找到常量 CreditCard并乐于使用它

【讨论】:

    猜你喜欢
    • 2022-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-18
    • 1970-01-01
    • 2022-09-24
    • 2011-10-15
    相关资源
    最近更新 更多