在第一个方法采用参数的情况下,如何使用Rspec“期望”方法链?

时间:2018-08-19 21:25:51

标签: ruby-on-rails ruby rspec mocking

我在ruby模型中有一个方法调用,如下所示:

$date = $date->format('Y-m-d')

在模型的spec.rb文件中,我试图模拟该调用并通过传入参数来获取值。但是我很难弄清楚调用它的正确方法。

在我的spec.rb文件顶部,有:

Contentful::PartnerCampaign.find_by(vanityUrl: referral_source).load.first

在describe块中,我尝试了以下操作:

 let(:first_double) { 
   double("Contentful::Model", fields {:promotion_type => "Promotion 1"}) 
 }

您可能会猜到,这些都不起作用。有人知道做这种事情的正确方法吗?甚至有可能吗?

3 个答案:

答案 0 :(得分:2)

一般来讲,我不希望使用存根链,因为它们通常表示您违反了Law of Demeter。但是,如果需要的话,这就是我模拟该序列的方式:

class Report_item(models.Model):
    owner = models.ForeignKey(settings.AUTH_USER_MODEL)
    title = models.CharField(max_length=255, help_text='*Title for the post e.g. item identity')
    item_type = models.CharField(default="", max_length=100,
                                 help_text='*Enter the item name you found e.g. Marksheet,key,wallet')
    location = models.CharField(max_length=60, help_text='*Enter the address/street where you find this item')
    city = models.CharField(max_length=60, help_text='*Enter the city name')
    date = models.DateTimeField(default=timezone.now)
    Description = models.TextField(blank=True,null=True,help_text='*Enter full description about item')
    publish = models.BooleanField(default=False)

    image = models.FileField(default="add Item image",
                             help_text='*Please uplocad a item image to identify by the owner')

    def __str__(self):
        return self.title + "      " + str(self.publish)

    def get_absolute_url(self):
        return reverse('feed:detail', kwargs={'pk': self.pk})

    class Meta:
        ordering = ["-date"]

答案 1 :(得分:0)

我认为您需要像这样在两行中重构链:

model    = double("Contentful::Model", fields: { promotion_type: "Promotion 1" }) 
campaign = double

allow(Contentful::PartnerCampaign).to receive(:find_by).with(vanityUrl: 'test_promo_path').and_return(campaign)
allow(campaign).to receive_message_chain(:load, :first).and_return(model)

然后,您可以编写将该属性传递给find_by的规范,并检查链条。

答案 2 :(得分:0)

这就是我要做的。请注意,我将“模拟”部分和“期望”部分分开,因为通常我会在下面有其他一些it示例(然后,我将需要那些it示例)相同的“模拟”逻辑),并且因为我希望它们具有单独的关注点:it示例中的任何内容通常都应该只专注于“预期”,因此,任何模拟或其他逻辑,我通常都会将它们放在it之外。

let(:expected_referral_source) { 'test_promo_path' }
let(:contentful_model_double) { instance_double(Contentful::Model, promotion_type: 'Promotion 1') }

before(:each) do
  # mock return values chain
  # note that you are not "expecting" anything yet here
  # you're just basically saying that: if Contentful::PartnerCampaign.find_by(vanityUrl: expected_referral_source).load.first is called, that it should return contentful_model_double
  allow(Contentful::PartnerCampaign).to receive(:find_by).with(vanityUrl: expected_referral_source) do
    double.tap do |find_by_returned_object|
      allow(find_by_returned_object).to receive(:load) do
        double.tap do |load_returned_object|
          allow(load_returned_object).to receive(:first).and_return(contentful_model_double)
        end
      end
    end
  end
end

it 'calls Contentful::PartnerCampaign.find_by(vanityUrl: referral_source).load.first' do
  expect(Contentful::PartnerCampaign).to receive(:find_by).once do |argument|
    expect(argument).to eq({ vanityUrl: expected_referral_source})

    double.tap do |find_by_returned_object|
      expect(find_by_returned_object).to receive(:load).once do
        double.tap do |load_returned_object|
          expect(load_returned_object).to receive(:first).once
        end
      end
    end
  end
end

it 'does something...' do
  # ...
end

it 'does some other thing...' do
  # ...
end

如果您不了解ruby的tap方法,请随时使用check this out