모의, 스텁, 스파이의 차이점

11472 단어 rspecrubytesting
이 게시물은 Mock, Stub, Spies의 차이점을 설명하고 RSpec을 사용하여 예제를 보여줍니다.

이것이 훌륭한 테스트를 작성하는 데 도움이 되기를 바랍니다!

TL;DR



this great article에서 Martin Fowler는 다음과 같이 말합니다.

Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test.

Spies are stubs that also record some information based on how they were called. One form of this might be an email service that records how many messages it was sent.

Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.



RSpec과의 차이점 보기



스텁



예를 들어 어떤 메서드가 타사 API에 의존하는 경우 테스트할 때마다 요청하는 것은 좋지 않습니다.
이 경우 스텁이 매우 유용합니다.

class SomeClient
  def request
    body = some_lib.request
    JSON.parse body
  end

  private

  def some_lib
    @some_lib ||= SomeLib.new
  end
end



describe 'SomeClient#request'
  before do
    allow(client).to receive(:some_lib).with(no_args).and_return(some_lib)
    allow(some_lib).to receive(:request).with(no_args).and_return(expected_boby)
  end

  let(:client) { SomeClient.new }
  let(:some_lib) { instance_double(SomeLib) }
  let(:expected_body) { ... }
  let(:expected_json) { JSON.parse expected_body }

  subject { client.request }

  it { is_expected.to eq expected_json }
end


실제로 스텁으로 API를 호출하는 것을 피할 수 있습니다.

모의



위의 스텁 예제에서 클라이언트가 실제로 API를 여러 번 호출하면 완전히 예상치 못한 것입니다.
some_lib 메서드가 예상대로 호출되는지 확인하려면 mock을 사용하는 것이 더 적합합니다.

describe 'SomeClient#request'
  before { allow(client).to receive(:some_lib).with(no_args).and_return(some_lib)  }

  let(:client) { SomeClient.new }
  let(:some_lib) { instance_double(SomeLib) }
  let(:expected_body) { ... }
  let(:expected_json) { JSON.parse expected_body }

  subject { client.request }

  it do
    expect(some_lib).to receive(:request).with(no_args).and_return(expected_boby).once # Ensure it's really called expectedly.
    is_expected.to eq expected_json
  end

SomeLib#request가 예기치 않게 호출되면(잘못된 인수, 여러 번 호출됨 등) 테스트가 실패합니다.

스파이


rspec-mocks 에서는 mock과 spy의 차이점을 명확히 하기가 조금 어렵지만...

RSpec 문서는 다음과 같이 말합니다.

Message expectations put an example's expectation at the start, before you've invoked the code-under-test. Many developers prefer using an arrange-act-assert (or given-when-then) pattern for structuring tests. Spies are an alternate type of test double that support this pattern by allowing you to expect that a message has been received after the fact, using have_received.



위의 예는 다음과 같은 스파이가 될 것입니다.

describe 'SomeClient#request'
  before { allow(client).to receive(:some_lib).with(no_args).and_return(some_lib)  }

  let(:client) { SomeClient.new }
  let(:some_lib) { instance_spy(SomeLib) } # It's OK to use `instance_double` instead, I describe the difference afterward.
  let(:expected_body) { ... }
  let(:expected_json) { JSON.parse expected_body }

  subject { client.request }

  it do
    is_expected.to eq expected_json
    expect(some_lib).to have_received(:request).with(no_args).and_return(expected_boby).once
  end
end


더 직관적일 수 있습니다.
subject가 호출된 후 테스트는 SomeLib#request가 실제로 예상대로 호출되었는지 확인합니다.
instance_spy(SomeLib)instance_double(SomeLib)와 유사합니다. 차이점은 다음과 같습니다.
  • instance_double
  • 메서드를 스텁할 수 있습니다.
  • 정의되지 않은 메서드를 스텁하려고 하면 오류가 발생합니다.

  • instance_spy
  • 스텁과 실제 개체를 혼합합니다.
  • 실제 메소드가 스텁되지 않은 경우 실제 메소드가 호출됩니다.


  • 요약



    차이점을 명확히하고 우수한 테스트를 작성합시다!

    참조


  • https://martinfowler.com/articles/mocksArentStubs.html
  • https://martinfowler.com/articles/mocksArentStubs.html
  • 좋은 웹페이지 즐겨찾기