如何测试/模拟与外部宝石交互的Trailblazer操作?

时间:2016-02-26 00:03:57

标签: ruby-on-rails ruby unit-testing rspec trailblazer

我非常喜欢开拓者的所有面向对象的美!

我有一个与gem(称为cpanel_deployer)交互的操作,可以在Web上进行外部操作。 (它为cpanel添加了一个插件域。)

class Website::Deploy < Trailblazer::Operation
  attr_reader :website, :cpanel

  def process(params)
    real_cpanel_add_domain
    website.cpanel = cpanel
    website.save
  end

  private

  def setup!(params)
    @cpanel = Cpanel.find(params[:cpanel_id])
    @website = website.find(params[:website_id])
  end

  def real_cpanel_add_domain
    cp_domain = CpanelDeployer::Domain.new(website.domain)
    cp_panel = CpanelDeployer::Panel.new(cpanel.host, cpanel.username, cpanel.password)

    res = cp_panel.add_domain(cp_domain)

    raise StandardError unless res
  end

end

cpanel_deloyer宝石已经过测试,所以我不需要在这里重新测试它的功能。但是为了测试操作,我想确保使用正确的args调用CpanelDeployer::Panel#add_domain。所以我想我应该嘲笑CpanelDeployer::Panel

我认为尝试使用any_instance_of是不好的做法。根据思想机器人,它通常被认为是代码味道...他们建议使用依赖注入。是否有一种在开拓者操作中使用依赖注入的好方法?对于这种情况,还有另一种最佳做法吗?

2 个答案:

答案 0 :(得分:0)

一个选项是在gem的类上存根:new并返回测试双精度数。这是什么样的:

  describe Website::Deploy do

    let(:cpanel) { Cpanel::Create.(cpanel: {
      host: 'cpanel-domain.com', username: 'user', password: 'pass'
    }).model }

    let(:website) { Website::Create.(website: { domain: 'domain.com' }).model }

    it 'works' do
      fake_cp_domain = double(CpanelDeployer::Domain)
      fake_cp = double(CpanelDeployer::Panel)

      expect(fake_cp).to receive(:add_domain).with(fake_cp_domain).and_return(true)

      expect(CpanelDeployer::Domain).to receive(:new)
        .with(website.domain)
        .and_return(fake_cp_domain)

      expect(CpanelDeployer::Panel).to receive(:new)
        .with(cpanel.host, cpanel.username, cpanel.password)
        .and_return(fake_cp)

      Website::Deploy.(cpanel_id: cpanel.id, website_id: website.id)
    end
  end

这看起来很麻烦......有更好的方法吗?

答案 1 :(得分:0)

老实说,我真的不明白real_cpanel_add_domain正在做什么,因为在我看来,它只是分配了两个局部变量,然后在其中一个上调用add_domain,这对它会有什么影响?

谈到依赖注入,我想你可以从params获取域和面板类,默认为CpanelDeployer::DomainCpanelDeployer::Panel,但在你的规范中传递一些存根。

我不喜欢使用new方法,因为它并不总是按预期工作。