Ruby on rails 如何在rails小测试中使用mock?

Ruby on rails 如何在rails小测试中使用mock?,ruby-on-rails,ruby,mocking,tdd,minitest,Ruby On Rails,Ruby,Mocking,Tdd,Minitest,有两个类,UserDevice(

有两个类,UserDevice( 在NotificationAdapter中,我使用AWS SDK,UserDevice使用NotificationAdapter实例。
接合点在下面

protected def notificationAdapter
  @notificationAdapter ||= NotificationAdapter.new(self)
end
在UserDevice测试中,我想制作临时NotificationAdapter模拟以替换原始NotificationAdapter,并仅在测试中使用此模拟。
但我不知道怎么做,因为这是我第一次在测试中使用mock

我认为这需要以下两个步骤

  • 在测试代码中生成临时NotificationAdapter类(NorificationAdapterMock)

    NotificationAdapterMock=MiniTest::Mock.new
    mock.expect:setEndpoint,“arn:testEndpoint”
    mock.expect:subscribeToAnnouncement,true

  • 将UserDevice的notificationAdapter方法更改为:

    受保护的def通知适配器
    @notificationAdapter | |=NotificationAdapterMock
    结束

  • 但我不知道这是对还是错。我该怎么办?

    你需要

  • mock
    您的
    NotificationAdapter
    ,因此它不会触发网络,而是做一些安全和简单的事情
  • 还要确保适配器接线正确
  • 旁注:请遵循,方法名称和变量应使用snake大小写,而不是camel大小写

    因此,我们可以这样写:

    require 'minitest/autorun'
    
    class NotificationAdapter
      def initialize(device)
        @device = device
      end
    
      def notify
        # some scary implementation, that we don't want to use in test
        raise 'Boo boo!'
      end
    end
    
    class UserDevice
      def notification_adapter
        @notification_adapter ||= NotificationAdapter.new(self)
      end
    
      def notify
        notification_adapter.notify
      end
    end
    
    describe UserDevice do
      it 'should use NotificationAdapter for notifications' do
        device = UserDevice.new
    
        # create mock adapter, that says 'ohai!' on notify
        mock_adapter = MiniTest::Mock.new
        mock_adapter.expect :notify, 'ohai!'
    
        # connect our mock, so next NoficationAdapter.new call will return our mock
        # and not usual implementation
        NotificationAdapter.stub :new, mock_adapter do
          device.notify.must_equal 'ohai!'
        end
      end
    end
    
    更多信息可在和的MiniTest文档中找到

    但我们不要就此止步!我建议您将您的业务逻辑从
    ActiveRecord
    模型转移到单独的服务类。这将产生以下良好效果:

  • 你的模特变瘦了
  • 该特性很好地封装在自己的类中,现在遵守单一责任原则
  • 您的测试变得异常快速,因为您不需要加载Rails,而是可以模拟您的模型
  • 这是:

    require 'minitest/autorun'
    
    # same adapter as above
    class NotificationAdapter
      def initialize(device)
        @device = device
      end
    
      def notify
        raise 'Boo boo!'
      end
    end
    
    class UserDevice
    # the logic has been moved out
    end
    
    class NotifiesUser
    
      def self.notify(device)
        adapter = NotificationAdapter.new(device)
        adapter.notify
      end
    end
    
    describe NotifiesUser do
      it 'should use NotificationAdapter for notifications' do
        # Let's mock our device since we don't need it in our test
        device = MiniTest::Mock.new
    
        # create mock adapter, that says 'ohai!' on notify
        mock_adapter = MiniTest::Mock.new
        mock_adapter.expect :notify, 'ohai!'
    
        # connect our mock, so next NoficationAdapter.new call will return our mock
        # and not usual implementation
        NotificationAdapter.stub :new, mock_adapter do
          NotifiesUser.notify(device).must_equal 'ohai!'
        end
      end
    end
    
    祝你今天愉快


    另外,如果你想了解更多关于隔离测试、模拟技术和一般的“FastRails测试”运动的知识,我强烈推荐你GaryBernhardt的屏幕广播。这是付费的东西,但非常值得。

    您的回答2(使用更薄的模型箱)是我问题的解决方案。但关于答案1,一个奇怪的未解决的问题仍然存在。我知道答案2更好,但这只是为了更好地了解活动记录测试。当我在测试代码中编写“UserDevice”类时,它不适用于带有活动记录的默认方法(可能它不继承活动记录库)。当我在测试代码中编写“UserDeviceapp/models目录中已经有
    UserDevice
    ,则不必在测试中写入任何内容。是的,我的app/models目录中有UserDevice,但它会在“UserDevice.new(user_id:1,…)”处引发初始化错误,并带有“错误的参数数(1代表0)”。似乎您构建的模型不正确。也许它没有正确加载,不看代码很难说。请看一下Rails测试指南:或在SO:)上发布另一个问题。另外,如果我的代码解决了您的问题,请将其标记为解决方案。谢谢。我发现了我的错误,我嘲笑了用户设备。现在一切都好了。你关于蛇形风格和SRP的建议非常有价值,因为它们一直在我的脑海中。你用一个答案解决了很多问题!