Пример RSpec Mock Object - PullRequest
       56

Пример RSpec Mock Object

37 голосов
/ 02 сентября 2010

Я плохо знаком с предметами, и пытаюсь научиться использовать их в RSpec.Может кто-нибудь опубликовать пример (пример приветственного типа объекта RSpec Mock) или ссылку (или любую другую ссылку) о том, как использовать API-интерфейс объекта RSpec?

Ответы [ 5 ]

64 голосов
/ 02 сентября 2010

Вот пример простой насмешки, которую я сделал для теста контроллера в приложении rails:

before(:each) do
  @page = mock_model(Page)
  @page.stub!(:path)
  @page.stub!(:find_by_id)
  @page_type = mock_model(PageType)
  @page_type.stub!(:name)
  @page.stub!(:page_type).and_return(@page_type)
end

В этом случае я высмеиваю модели Page & PageType (объекты), а также заглушаюиз нескольких методов, которые я вызываю.

Это дает мне возможность выполнять такие тесты:

it "should be successful" do
  Page.should_receive(:find_by_id).and_return(@page)
  get 'show', :id => 1
  response.should be_success
end

Я знаю, что этот ответ более специфичен для рельсов, но я надеюсь, что он поможетвас немного.


Редактировать

Хорошо, так что вот пример Привет мир ...

Учитывая следующий скрипт (hello.rb):

class Hello
  def say
    "hello world"
  end
end

Мы можем создать следующую спецификацию (hello_spec.rb):

require 'rubygems'
require 'spec'

require File.dirname(__FILE__) + '/hello.rb'

describe Hello do
  context "saying hello" do 
    before(:each) do
      @hello = mock(Hello)
      @hello.stub!(:say).and_return("hello world")
    end

    it "#say should return hello world" do
      @hello.should_receive(:say).and_return("hello world")
      answer = @hello.say
      answer.should match("hello world")
    end
  end
end
6 голосов
/ 19 сентября 2016

mock устарела на основе этого github pull .

Теперь вместо этого мы можем использовать double - больше здесь ...

 before(:each) do
   @page = double("Page")
   end

  it "page should return hello world" do
    allow(@page).to receive(:say).and_return("hello world")
    answer = @page.say
    expect(answer).to eq("hello world")
  end
5 голосов
/ 14 апреля 2013

У меня недостаточно очков, чтобы оставить комментарий к ответу, но я хотел сказать, что принятый ответ также помог мне понять, как заглушить случайное значение.

Мне нужно было иметь возможность заглушить значение экземпляра объекта, которое назначается случайным образом, например:

class ClumsyPlayer < Player do

  def initialize(name, health = 100)
    super(name, health)
    @health_boost = rand(1..10)
  end
end

Тогда в моей спецификации у меня возникла проблема с выяснением, как заглушить случайное здоровье случайного игрока, чтобы проверить, что, когда они получают лечение, они получают надлежащее повышение своего здоровья.

Трюк был:

@player.stub!(health_boost: 5)

Так что stub! был ключом, я просто использовал stub и все еще получал случайные проходы rspec и сбои.

Так что спасибо, Брайан

1 голос
/ 10 апреля 2018

Обычно вы хотите использовать Mock Object, когда вы хотите делегировать некоторые функциональные возможности другому объекту, но вы не хотите проверять реальную функциональность вашего текущего теста, поэтому вы заменяете этот объект другим, которым легче управлять.Давайте назовем этот объект «зависимостью» ...

То, что вы тестируете (объект / метод / функция ...), может взаимодействовать с этой зависимостью, вызывая методы для ...

  • Запрос чего-либо.
  • Изменение чего-либо или создание какого-либо побочного эффекта.

При вызове метода для запроса чего-либо

Когда вы используете зависимостьчтобы «запросить» что-то, вам не нужно использовать «фиктивный API», потому что вы можете просто использовать обычный объект и проверить ожидаемый результат в тестируемом объекте ... например:

describe "Books catalog" do
  class FakeDB
    def initialize(books:)
      @books = books
    end

    def fetch_books
      @books
    end
  end

  it "has the stored books" do
    db = FakeDB.new(books: ["Principito"])
    catalog = BooksCatalog.new(db)
    expect(catalog.books).to eq ["Principito"]
  end
end

При вызове метода для изменения чего-либо или создания какого-либо побочного эффекта ...

Когда вы хотите изменить свою зависимость или сделать что-то с побочными эффектами, такими как вставка новой записи вбаза данных, отправка электронного письма, внесение платежа и т. д. ... теперь вместо того, чтобы проверять, было ли произведено изменение или побочный эффект, вы просто проверяете, что вызываете правильную функцию / метод с правильными атрибутами ... for пример:

describe "Books catalog" do
  class FakeDB
    def self.insert(book)
    end
  end

  def db
    FakeDB
  end

  it "stores new added books" do
    catalog = BooksCatalog.new(db)

    # This is how you can use the Mock API of rspec
    expect(db).to receive(:insert).with("Harry Potter")

    catalog.add_book("Harry Potter")
  end
end

Это базовый пример, но вы можете многое сделать, просто используя эти знания =)

Я написал пост с этим содержанием и еще немногочто может быть полезно http://bhserna.com/2018/how-and-when-to-use-mock-objects-with-ruby-and-rspec.html

1 голос
/ 28 августа 2016

Текущий (3.x) RSpec предоставляет как чистые фиктивные объекты (как в ответ Тохи ), так и частичные имитации (имитирующие вызовы существующего объекта).Вот пример частичной насмешки.Он использует expect и receive для насмешки вызова Order на CreditCardService, поэтому тест проходит только в том случае, если вызов сделан без необходимости его фактического выполнения.

class Order
  def cancel
     CreditCardService.instance.refund transaction_id
  end
end

describe Order do
  describe '#cancel' do
    it "refunds the money" do
      order = Order.new
      order.transaction_id = "transaction_id"
      expect(CreditCardService.instance).to receive(:refund).with("transaction_id")
      order.cancel
    end
  end
end

В этом примере макет находится на возвращаемом значении CreditCardService.instance, которое предположительно является одиночным.

with необязательно;без него любой вызов refund будет соответствовать ожиданиям.Возвращаемое значение может быть дано с помощью and_return;в этом примере он не используется, поэтому вызов возвращает nil.


В этом примере используется текущий (expect .to receive) синтаксический синтаксис RSpec, который работает с любым объектом.В принятом ответе используется старый метод rspec-rails mock_model, который был характерен для моделей ActiveModel и был перемещен из rspec-rails в другой гем.

...