【发布时间】:2017-11-15 23:15:38
【问题描述】:
我遇到了一个问题,我试图模拟服务类中的异步方法,但我希望结果集基于调用的输入。
例如:
allow_any_instance_of(Emails::EmailService)
.to receive(:send_many_async)
.and_wrap_original { |m, *args| args[1].map { |recipient| Emails::EmailResult.new(recipient.email) } }
这个方法的签名是send_many_async(email, users)
我不认为and_wrap_original 的行为与我预期的一样,当我打印出m 和args 的值时,我看到了:
#<Method: Emails::EmailService#__send_many_async_without_any_instance__(send_many_async)>
#<Emails::EmailService:0x007fa5c4e1b448>
#<Emails::MyEmail:0x007fa5c4e1b4e8>
如,我希望arg[0] 是email 对象,arg[1] 是用户列表——而不是arg[0] 是我正在模拟的服务,并且没有用户列表完全没有(例如:arg[2])
我实际上只是想确认调用了该方法,并且用户是我希望他们成为的人数。
或者,如果我可以将同一类上的另一个方法替换为另一个也可以工作的方法(非异步调用),但我无法找到将:send_many_async 替换为常规:send_many 的方法以另一种方式成功模拟(我不能在这里申请)
有人成功地做这样的事情吗?我期待 and_wrap_original 提供传递给实例方法的内容,但显然我在这方面感到困惑。
编辑
如果有人想知道,这里有一个有效的测试样本。不幸的是,它在我的应用程序中还没有为我工作,但其他人可能会觉得它有帮助。
class TestEmailSvc
def send_many_async(email, to_email_users, from_email_user: nil, send_at: nil)
puts 'Real one called!'
end
end
class TestEmail
end
class TestEmailUser
attr_reader :email
def initialize(email)
@email = email
end
end
class TestEmailResult
attr_reader :user
def initialize(user)
@user = user
end
def status
:pending
end
end
describe 'Test Spec' do
it 'tests my mock' do
allow_any_instance_of(TestEmailSvc)
.to receive(:send_many_async)
.and_wrap_original { |m, _, args| args.map { |recipient| TestEmailResult.new(recipient) } }
svc = TestEmailSvc.new
users = [
TestEmailUser.new('email 1'),
TestEmailUser.new('email 2')
]
results = svc.send_many_async(TestEmail.new, users)
expect(results.count).to eql 2
end
end
【问题讨论】:
标签: ruby-on-rails ruby unit-testing rspec