【问题标题】:How can I use mock in my rails minitest?如何在我的 rails minitest 中使用 mock?
【发布时间】:2015-09-10 06:07:37
【问题描述】:

有两个类,UserDevice( 在 NotificationAdapter 中,我使用 AWS SDK,而 UserDevice 使用 NotificationAdapter 实例。
关节点在下方,

protected def notificationAdapter
  @notificationAdapter ||= NotificationAdapter.new(self)
end

在 UserDevice 测试中,我想制作临时 NotificationAdapter 模拟来替换原来的 NotificationAdapter,并且只在测试中使用这个模拟。
但我不知道该怎么做,因为这是我在测试中使用模拟的第一个案例。

我认为它需要以下两个步骤,

  1. 在测试代码中制作临时 NotificationAdapter 类(NorificationAdapterMock)。

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

  2. 将UserDevice的notificationAdapter方法改成下面,

    protected def notificationAdapter @notificationAdapter ||= NotificationAdapterMock end

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

【问题讨论】:

    标签: ruby-on-rails ruby mocking tdd minitest


    【解决方案1】:

    你需要

    1. mock 你的 NotificationAdapter,所以它不会触发网络,而是做一些安全和简单的事情
    2. 还要确保您的适配器接线正确

    旁注:请关注ruby style guidelines,方法名称和变量应使用蛇形而不是驼形。

    所以,我们可以这样写:

    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 的 mocksstubs 文档中找到。

    但我们不要停在这里!我建议您将业务逻辑从 ActiveRecord 模型中移出到单独的服务类中。这样会有以下好的效果:

    1. 您的模型变薄了
    2. 功能很好地封装在自己的类中,现在遵守单一职责原则
    3. 您的测试变得异常快,因为您不需要加载 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
    

    祝你有美好的一天!

    附:如果您想了解更多关于隔离测试、模拟技术和一般“快速轨道测试”运动的信息,我强烈推荐您 Gary Bernhardt 的 destroyallsoftware.com 截屏视频。这是付费的东西,但非常值得。

    【讨论】:

    • 您的答案2(带有更薄的模型案例)是我问题的解决方案。但是关于 answer1 的一个奇怪的未解决的事情仍然存在。我理解 answer2 更好,但这只是为了更多地了解活动记录测试。当我在测试代码中编写“UserDevice”类时,它不适用于具有活动记录的默认方法(可能它不继承活动记录库)。并且当我在测试代码中编写“UserDevice
    • 很抱歉我之前没有解释清楚。您不应该在测试代码中编写真正的实现,我将其放在这里仅供参考,以便您一次掌握所有代码。如果您的app/models 目录中已经有UserDevice,则无需在测试中编写任何内容。
    • 是的,我的 app/models 目录中有 UserDevice,但它会在 'UserDevice.new(user_id: 1, ...)' 处引发初始化错误,并带有'错误数量的参数(1 代表 0) '。
    • 您的模型构建似乎不正确。也许它没有正确加载,如果不看你的代码就很难说。看看这个在 Rails 中测试的指南:guides.rubyonrails.org/testing.html 或在 SO 上发布另一个问题 :)。另外,如果我的代码解决了您的问题,请将其标记为解决方案。谢谢。
    • 我发现我的错误,我做了一个 UserDevice 的模拟。所以现在一切正常。你对蛇风格和 SRP 的建议非常有价值,因为它们一直在我脑海中。你在一个答案中解决了很多问题!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-20
    • 2017-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多