如何在我的 rails minitest 中使用 mock?
How can I use mock in my rails minitest?
有两个 class,UserDevice(< ActiveRecord::Base) 和 NotificationAdapter。
在NotificationAdapter中,我使用AWS SDK,而UserDevice使用NotificationAdapter实例。
关节点在下方,
protected def notificationAdapter
@notificationAdapter ||= NotificationAdapter.new(self)
end
在UserDevice测试中,我想做一个临时的NotificationAdapter mock来替换原来的NotificationAdapter,并且只在测试中使用这个mock。
但我不知道该怎么做,因为这是我在测试中使用模拟的第一个案例。
我觉得需要下面两步,
在测试代码中创建临时 NotificationAdapter class(NorificationAdapterMock)。
NotificationAdapterMock = MiniTest::Mock.new
mock.expect :setEndpoint, 'arn:testEndpoint'
mock.expect :subscribeToAnnouncement, true
将UserDevice的notificationAdapter方法改成下面,
protected def notificationAdapter
@notificationAdapter ||= NotificationAdapterMock
end
但不知道是对是错。我该怎么办?
你需要
mock
你的 NotificationAdapter
,所以它不会触发网络,而是做一些安全和简单的事情
- 还要确保您的适配器接线正确
旁注:请遵循 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
可以在 mocks and stubs 上的 MiniTest 文档中找到更多信息。
但我们不要就此打住!我建议您将业务逻辑从 ActiveRecord
模型移出到单独的服务 class。这样会有以下好的效果:
- 你的模特变瘦了
- 功能很好地封装在它自己的 class 中并且现在遵守单一职责原则
- 您的测试变得非常快,因为您不需要加载 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
祝你有愉快的一天!
P.S。如果您想了解更多关于隔离测试、模拟技术和一般 "fast rails tests" 运动的信息,我强烈推荐您观看 Gary Bernhardt 的 destroyallsoftware.com 截屏视频。这是付费的东西,但是非常值得。
有两个 class,UserDevice(< ActiveRecord::Base) 和 NotificationAdapter。
在NotificationAdapter中,我使用AWS SDK,而UserDevice使用NotificationAdapter实例。
关节点在下方,
protected def notificationAdapter
@notificationAdapter ||= NotificationAdapter.new(self)
end
在UserDevice测试中,我想做一个临时的NotificationAdapter mock来替换原来的NotificationAdapter,并且只在测试中使用这个mock。
但我不知道该怎么做,因为这是我在测试中使用模拟的第一个案例。
我觉得需要下面两步,
在测试代码中创建临时 NotificationAdapter class(NorificationAdapterMock)。
NotificationAdapterMock = MiniTest::Mock.new mock.expect :setEndpoint, 'arn:testEndpoint' mock.expect :subscribeToAnnouncement, true
将UserDevice的notificationAdapter方法改成下面,
protected def notificationAdapter @notificationAdapter ||= NotificationAdapterMock end
但不知道是对是错。我该怎么办?
你需要
mock
你的NotificationAdapter
,所以它不会触发网络,而是做一些安全和简单的事情- 还要确保您的适配器接线正确
旁注:请遵循 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
可以在 mocks and stubs 上的 MiniTest 文档中找到更多信息。
但我们不要就此打住!我建议您将业务逻辑从 ActiveRecord
模型移出到单独的服务 class。这样会有以下好的效果:
- 你的模特变瘦了
- 功能很好地封装在它自己的 class 中并且现在遵守单一职责原则
- 您的测试变得非常快,因为您不需要加载 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
祝你有愉快的一天!
P.S。如果您想了解更多关于隔离测试、模拟技术和一般 "fast rails tests" 运动的信息,我强烈推荐您观看 Gary Bernhardt 的 destroyallsoftware.com 截屏视频。这是付费的东西,但是非常值得。