Ruby on rails 如何在rspec中对控制器进行修补?

Ruby on rails 如何在rspec中对控制器进行修补?,ruby-on-rails,ruby-on-rails-4,rspec,Ruby On Rails,Ruby On Rails 4,Rspec,场景 存在并发性可能导致重复密钥错误的争用情况。例如: def before_create_customer_by_external_id end def create_customer_from_external_id(external_id = nil) @customer = current_account.customers.create!(external_id: external_id || @external_id) end def set_new_or_old_custo

场景

存在并发性可能导致重复密钥错误的争用情况。例如:

def before_create_customer_by_external_id
end

def create_customer_from_external_id(external_id = nil)
  @customer = current_account.customers.create!(external_id: external_id || @external_id)
end

def set_new_or_old_customer_by_external_id
  if @customer.blank?
    before_create_customer_by_external_id
    create_customer_from_external_id
  end
rescue ActiveRecord::RecordInvalid => e
  raise e unless Customer.external_id_exception?(e)
  @customer = current_account.customers.find_by_external_id(@external_id)
end
测试

现在,为了测试竞赛案例(基于的答案),我们只需要在通过外部id创建客户之前使用monkey patch
,调用
从外部id创建客户

问题


如何做到这一点而不重写整个类并出现“method not found”(方法未找到)错误?

经过深入研究,我提出了以下解决方案:

context 'with race condition' do
  it 'should hit race case and do what is expected' do
    ControllerToOverride.class_eval do
      def before_create_new_customer_by_external_id
        create_customer_from_external_id
      end
    end

    # ...expect...

    ControllerToOverride.class_eval do
      undef before_create_new_customer_by_external_id
    end
  end
end
我通过使用代码覆盖率工具和调试语句验证了它是否达到了要求

很高兴知道这里有没有更干净的路

编辑2020-04-24 根据注释,我们应该
unde
这个方法,这样它就不会影响后续的测试。参考:


我没有验证这一点,因为我不再有这个测试套件。请让我知道它是否有效。

经过一些挖掘,我想出了以下解决方案:

context 'with race condition' do
  it 'should hit race case and do what is expected' do
    ControllerToOverride.class_eval do
      def before_create_new_customer_by_external_id
        create_customer_from_external_id
      end
    end

    # ...expect...

    ControllerToOverride.class_eval do
      undef before_create_new_customer_by_external_id
    end
  end
end
我通过使用代码覆盖率工具和调试语句验证了它是否达到了要求

很高兴知道这里有没有更干净的路

编辑2020-04-24 根据注释,我们应该
unde
这个方法,这样它就不会影响后续的测试。参考:


我没有验证这一点,因为我不再有这个测试套件。如果它不起作用,请告诉我。

monkey修补类的一个步骤是创建一个:

这与您的解决方案没有太大区别,但可以将monkeypatch隔离到该上下文块

您可能不需要自定义路由块-rspec为rest方法(编辑、显示、索引等)设置一些虚拟路由


如果此上下文位于
descripe ControllerToOverride
块内,则控制器的参数是可选的,除非您已关闭
config。为匿名控制器推断\u base\u class\u
从monkey修补类开始的步骤是创建:

这与您的解决方案没有太大区别,但可以将monkeypatch隔离到该上下文块

您可能不需要自定义路由块-rspec为rest方法(编辑、显示、索引等)设置一些虚拟路由


如果此上下文位于
descripe ControllerToOverride
块内,则控制器的参数是可选的,除非您已关闭
config。为匿名控制器推断基本类,这也将更改后续规范的类-随机规范排序,影响可能是confusing@FrederickCheung我在后面添加了一个
undef
,我相信这将解决这个问题。这也将改变后续规范的类-随机规范排序,效果可能会更好confusing@FrederickCheung我在后面添加了一个
undef
,我相信这会解决这个问题“undefined method`controller'for#(NoMethodError)”。这实际上是扩展(通过正确的继承)还是替换控制器?这将创建控制器的匿名子类。只有在标记为控制器规范的规范中,才能调用此方法。我为#(NoMethodError)获得了一个“undefined method`controller”“用这个。这实际上是扩展(通过正确的继承)还是替换控制器?这会创建控制器的匿名子类。只有在被标记为控制器规范的规范中,才能调用此函数。