如何在rspec

时间:2018-07-18 11:47:40

标签: ruby rspec

我在使用外部api时遇到问题,下面是示例

require 'rspec'
require 'google/apis/storage_v1'

module Google
  class Storage
    def upload file
      puts '#' * 90
      puts "File #{file} is uploaded to google cloud"
    end
  end
end

class UploadWorker
  include Sidekiq::Worker

  def perform
    Google::Storage.new.upload 'test.txt'
  end
end


RSpec.describe UploadWorker do

  it 'uploads to google cloud' do
    google_cloud_instance = double(Google::Storage, insert_object: nil)
    expect(google_cloud_instance).to receive(:upload)
    worker = UploadWorker.new
    worker.perform
  end
end

我正在尝试对Google :: Storage类进行存根。此类在被测试的对象内实例化。如何验证此实例上的邮件期望?

在上面的示例中运行时,我得到以下输出,这似乎合乎逻辑,我的double值未被测试对象使用

(Double Google::Storage).upload(*(any args))
           expected: 1 time with any arguments
           received: 0 times with any arguments

我是Rspec的新手,在此方面遇到困难,我们将不胜感激。

谢谢!

2 个答案:

答案 0 :(得分:4)

达到DI始终是一个好主意(https://stackoverflow.com/a/51401376/299774),但有时由于某些原因您可能无法做到这一点,因此这是在不更改“生产”代码的情况下进行存根的另一种方法。

1。 expect_any_instance_of

it 'uploads to google cloud' do
  expect_any_instance_of(Google::Storage).to receive(:insert_object)
  worker = UploadWorker.new
  worker.perform
end

如果您只想测试该方法是否在任何此类对象上调用该方法。

2。更加精细的设置

如果您想控制或设置更多期望,可以这样做

  it 'uploads to google cloud' do
    the_double = instance_double(Google::Storage)
    expect(Google::Storage).to receive(:new).and_return(the_double)
       # + optional `.with` in case you wanna assert stuff passed to the constructor
    expect(the_double).to receive(:insert_object)
    worker = UploadWorker.new
    worker.perform
  end

再次-依赖注入更加清晰,您应该为此而努力。这是另一种可能性。

答案 1 :(得分:2)

我会考虑进行依赖注入,例如:

#import "PopUpViewController.h"

@interface PopUpViewController ()

@end

@implementation PopUpViewController

- (void)viewDidLoad {
  self.view.backgroundColor=[[UIColor blackColor]     colorWithAlphaComponent:.6];
self.popUpView.layer.cornerRadius = 5;
self.popUpView.layer.shadowOpacity = 0.8;
self.popUpView.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
self.popUpView.clipsToBounds = YES;
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
// Do any additional setup after loading the view from its nib.
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

#pragma animation

- (void)showAnimate
{
self.view.transform = CGAffineTransformMakeScale(1.3, 1.3);
self.view.alpha = 0;
[UIView animateWithDuration:.25 animations:^{
    self.view.alpha = 1;
    self.view.transform = CGAffineTransformMakeScale(1, 1);
}];
}

- (void)removeAnimate
{
[UIView animateWithDuration:.25 animations:^{
    self.view.transform = CGAffineTransformMakeScale(1.3, 1.3);
    self.view.alpha = 0.0;
} completion:^(BOOL finished) {
    if (finished) {
        [self.view removeFromSuperview];
    }
}];
}



- (void)showInView:(UIView *)aView animated:(BOOL)animated
{
[aView addSubview:self.view];
if (animated) {
    [self showAnimate];
}
}

- (IBAction)closePopup:(id)sender {
NSLog(@"closing...");
[self removeAnimate];
}


@end

然后您可以在规范中添加一个double:

class UploadWorker
  def initialize(dependencies = {})
    @storage = dependencies.fetch(:storage) { Google::Storage }
  end

  def perform
    @storage.new.upload 'test.txt'
  end
end

如果不是使用初始化程序,则可以使用getter / setter方法注入依赖项:

storage = double
expect(storage).to receive(...) # expection
worker = UploadWorker.new(storage: storage)
worker.perform

以及在规格中:

def storage=(new_storage)
  @storage = new_storage
end

def storage
  @storage ||=  Google::Storage
end