RSpec에서 모의(mock)란 무엇입니까?
(또는 이것은 RSpec 고유의 개념이 아니기 때문에 일반적으로 모의입니다.)
모의는 테스트에 사용되는 개체입니다. .
모의 객체를 사용하여 두 객체 간의 상호 작용을 테스트합니다. 일반적인 기대에서와 같이 출력 값을 테스트하는 대신.
예를 들어 :
이미지를 뒤집는 API를 작성 중입니다.
자신의 이미지 조작 코드를 작성하는 대신 mini_magick
과 같은 gem을 사용합니다. .
코드와 이 외부 종속성 간의 상호 작용을 테스트하려고 합니다. ... 따라서 ImageProcessor
에서 올바른 메서드가 호출될 것으로 예상하는 모의를 작성합니다. 수업.
즉, 테스트를 실행할 때마다 이미지를 뒤집지 않을 것입니다(느린 작업).
어떻게 작동하나요?
Mock은 원래 객체를 대체하므로 실제 메소드는 호출되지 않습니다.
몇 가지 코드 예제를 볼 시간입니다!
RSpec 모의 예제
다음은 ImageFlipper
입니다. 테스트:
RSpec.describe "ImageFlipper" do it "정확한 인수로 flip 메소드를 호출" do mock =double("mini_magick") expect(mock).to receive(:flip).with("ruby.jpg") img =ImageFlipper.new(모의) img.flip("ruby.jpg") 끝
이 테스트를 통해 TDD를 사용하여 코드를 작성할 수 있습니다.
첫 번째 :
ImageFlipper
를 작성해야 합니다. 수업.
좋아요 :
클래스 ImageFlipper def initialize(image_processor) @image_processor =image_processor endend
flip
도 필요합니다. 방법:
데프 플립(file_name)종료
이제 RSpec에서 다음과 같은 피드백을 받습니다.
Failures:1) ImageFlipper는 올바른 인수로 flip 메소드를 호출합니다. Failure/Error:expect(mock).to receive(:flip).with("ruby.jpg") (Double "mini_magick").flip(" ruby.jpg") 예상:인수 포함 1회:("ruby.jpg") 수신:0회 # ./rspec-mocks.rb:6:in `블록(2 레벨) in'사전> 이것은
flip
메서드가 0번 호출되었지만 1번 호출될 것으로 예상되었습니다.원하는 대로 테스트를 통과할 수 있습니다. :
def flip(file_name) @image_processor.flip(file_name)end자, 합격 테스트가 있습니다. :
.0.00751초 만에 완료(파일 로드에 0.11157초 소요)1 예시, 0개 실패검토해 봅시다:여기서 우리는 무엇을 하였습니까?
ImageFlipper
를 만들었습니다.image_processor
를 사용하는 클래스 .이 프로세서는
flip
에 응답합니다. 방법.우리는 이 메서드가 인수와 함께 한 번 호출되었는지 테스트하기 위해 mock을 사용합니다.
알겠습니다.
이 예는 간단합니다.
하지만
ImageFlipper
의 완전한 구현을 상상할 수 있습니다. 파일이 있는지, 유효한 이미지인지 등을 확인합니다.모의 테스트와 가치 테스트의 차이점
일반 테스트에서 메소드의 반환 값을 확인합니다. :
<블록 인용>"이 메서드가 뒤집힌 이미지를 반환했습니까?"
모의를 사용할 때 행동을 테스트하고 있습니다 :
<블록 인용>"올바른 정보와 필요한 시간을 가지고 다른 사람들에게 올바른 행동을 알려 주었습니까?"
모의 대 스텁
또 다른 혼동 포인트는 모의 객체와 스텁을 비교하는 것입니다.
차이점은 무엇입니까?
- 스텁은 미리 준비된 답변이 포함된 메서드일 뿐이며 행동에는 관심이 없습니다.
- 모의는 메서드가 호출될 것으로 예상하며 호출되지 않으면 테스트가 실패합니다.
RSpec의 스텁입니다. :
stub =double("json")allow(stub).to receive(:response) do {"blog"=>"rubyguides.com", "rating"=>"5/5"}.to_jsonend사전>
allow
메소드는 이것을 스텁으로 만듭니다.테스트 개체
double("json")
을 허용합니다. 이 메서드를 수신하고 응답하지만 호출 여부를 확인하지 않습니다 .이것이 바로 차이점입니다!
검증된 복식 사용 방법
mocks &stubs의 단점 중 하나는 프로덕션 코드에 존재하지 않는 메소드를 사용하게 될 수 있다는 것입니다.
메소드 이름이 변경되었거나... 오타가 있을 수 있습니다!
검증된 복식 만나기 .
검증된 double은 스텁(
allow
) 또는 모의(expect
) &이 이름의 메소드가 있는지 확인합니다.예 :
모의 =instance_double(ImageProcessor)메서드가 없으면 오류가 발생합니다.
1) ImageFlipper는 올바른 인수로 flip 메소드를 호출합니다. Failure/Error:expect(mock).to receive(:flip).with("ruby.jpg") ImageProcessor 클래스는 인스턴스 메소드를 구현하지 않습니다:flip사전>그러나 메소드가 존재하면 올바르게 작동합니다.
모의 반환 값
조롱으로 돌아가자.
마지막 예에서 우리는 이것을 가지고 있었습니다:
예상(모의).수신(:flip).with("ruby.jpg")코드가
flip
을 호출할 때 , 모의는nil
을 반환합니다. .코드가 nil 이외의 값을 예상하면 오류가 발생합니다.
모의 결과를 반환하여 이 문제를 해결할 수 있습니다.
좋아요 :
예상(모의).수신(:flip).with("ruby.jpg").and_return("ruby-flipped.jpg")인스턴스 메소드를 조롱하는 방법
다음과 같은 코드가 있다고 가정해 보겠습니다.
클래스 NumberGenerator def random "A" * rand(1..10) endend이 방법은 무작위성 때문에 테스트하기 어렵습니다.
RSpec을 사용하면
rand
를 조롱하거나 스텁할 수 있습니다. .좋아요 :
"난수 생성" do generator =NumberGenerator.new allow(generator).to receive(:rand).and_return(5) expect(generator.random).to eq("AAAAAA")end지금 :
rand
메서드의 결과를 테스트하는 데 사용할 수 있도록 고정 값을 반환합니다.이상적으로는 종속성(
rand
기능, 이 경우) 제어할 수 있습니다. 종속성을 주입한다는 것은 매개변수로 전달한다는 의미입니다. , 멋진 것은 없습니다.그러나 때로는 메서드를 스텁하는 것이 더 편리합니다.
모의를 언제 사용해야 하나요?
이제 중요한 질문에 대해...
정확히 언제 mock을 사용해야 하나요?
소프트웨어 개발은 복잡한 주제입니다.
하지만 따를 수 있는 몇 가지 지침이 있습니다. :
- 테스트 중인 메서드가 값을 반환하고 부작용(파일 생성, API 요청 생성 등)이 없으면 모의 객체가 필요하지 않습니다. 반환 값을 확인하기만 하면 됩니다.
- 메소드가 외부 개체와 함께 작동하고 외부 개체에 명령을 보내는 경우 이러한 개체와의 상호 작용을 조롱할 수 있습니다.
- 방법이 외부 서비스(예:API)에서 데이터를 요청하는 경우 스텁을 사용하여 테스트 목적으로 이 데이터를 제공할 수 있습니다.
외부 세계와의 상호작용을 위한 조롱을 예약하려는 경우 .
즉...
자신의 애플리케이션 클래스를 조롱하지 마세요!
왜?
이는 테스트를 구현 세부정보와 결합하는 것을 촉진하고 코드를 변경하기 어렵게 만듭니다 .
유일한 예외는 타사 코드의 래퍼인 클래스입니다.
자세히 알아보려면 이 동영상을 시청하세요. :
요약
RSpec 모의, 스텁 및 검증된 복식에 대해 배웠습니다!
이 기사를 공유하세요. 더 많은 사람들이 이 콘텐츠를 즐기고 혜택을 받을 수 있도록.
읽어주셔서 감사합니다 🙂