development

RSpec let ()을 언제 사용합니까?

big-blog 2020. 2. 17. 22:22
반응형

RSpec let ()을 언제 사용합니까?


인스턴스 변수를 설정하기 위해 before 블록을 사용하는 경향이 있습니다. 그런 다음 예제에서 해당 변수를 사용합니다. 나는 최근에왔다 let(). RSpec 문서에 따르면

... 메모 화 된 헬퍼 메소드를 정의합니다. 값은 동일한 예제에서 여러 호출에 걸쳐 캐시되지만 예제에서는 캐시되지 않습니다.

이전 블록에서 인스턴스 변수를 사용하는 것과 어떻게 다른가요? 또한 언제 let()vs 를 사용해야 before()합니까?


나는 let두 가지 이유로 항상 인스턴스 변수를 선호 합니다.

  • 인스턴스 변수는 참조 될 때 존재합니다. 즉, 인스턴스 변수의 맞춤법을 세게 두드리면 새 변수가 작성되고로 초기화 nil되어 미묘한 버그와 오 탐지로 이어질 수 있습니다. let메소드를 작성하기 때문에 NameError철자가 틀렸을 때 얻을 수 있습니다. 또한 사양을 쉽게 리팩토링 할 수 있습니다.
  • before(:each)의 예는 후크에 정의 된 인스턴스 변수를 사용하지 않는 경우에도 후크, 각각의 예를하기 전에 실행됩니다. 일반적으로 큰 문제는 아니지만 인스턴스 변수 설정에 시간이 오래 걸리면 사이클이 낭비됩니다. 로 정의 된 메소드의 let경우 초기화 코드는 예제에서 호출 한 경우에만 실행됩니다.
  • 예제의 참조 구문을 변경하지 않고 예제의 로컬 변수에서 직접 let으로 리팩토링 할 수 있습니다. 인스턴스 변수를 리팩토링하는 경우 예제에서 객체를 참조하는 방법을 변경해야합니다 (예 :) @.
  • 이것은 약간 주관적이지만 Mike Lewis가 지적했듯이 스펙을 더 쉽게 읽을 수 있다고 생각합니다. 나는 모든 의존적 인 객체를 정의하고 블록을 멋지고 짧게 let유지 하는 조직을 좋아합니다 it.

관련 링크는 여기에서 찾을 수 있습니다 : http://www.betterspecs.org/#let


인스턴스 변수 및 사용의 차이 let()즉이 let()있다 으르 평가 . 이는 let()정의 된 메소드가 처음 실행될 때까지 평가되지 않음을 의미합니다 .

의 차이 before와는 letlet()당신에게 '계단식'스타일 변수의 그룹을 정의하는 좋은 방법을 제공합니다. 이렇게하면 코드를 단순화하여 사양이 조금 나아 보입니다.


let ()을 사용하기 위해 rspec 테스트에서 인스턴스 변수의 모든 사용을 완전히 대체했습니다. 나는 작은 Rspec 클래스를 가르치기 위해 그것을 사용했던 친구를 위해 간단한 예제를 작성했습니다 : http://ruby-lambda.blogspot.com/2011/02/agile-rspec-with-let.html

여기에있는 다른 답변 중 일부에서 알 수 있듯이 let ()은 지연 평가되므로로드 해야하는 것만로드합니다. 사양을 건조시키고 더 읽기 쉽게 만듭니다. 실제로 Rspec let () 코드를 inherited_resource gem 스타일로 컨트롤러에서 사용하도록 포팅했습니다. http://ruby-lambda.blogspot.com/2010/06/stealing-let-from-rspec.html

게으른 평가와 함께 ActiveSupport :: Concern 및 모든 사양 / 지원 / 동작과 결합 된 다른 장점은 응용 프로그램에 맞는 고유 한 사양 미니 DSL을 만들 수 있다는 것입니다. 랙 및 RESTful 리소스에 대한 테스트를 위해 작성했습니다.

내가 사용하는 전략은 Factory-everything입니다 (Machinist + Forgery / Faker를 통해). 그러나 before (: each) 블록과 함께 사용하여 전체 예제 그룹 세트에 대해 팩토리를 사전로드하여 스펙을 더 빠르게 실행할 수 있습니다. http://makandra.com/notes/770-taking-advantage -rspec-s-let-in-before-blocks


let 이 게으르게 평가되고 부작용 방법을 넣지 말아야 한다는 것을 명심해야 합니다. 그렇지 않으면 let 에서 before (: each)로 쉽게 변경할 수 없습니다 . let 을 사용할 수 있습니다 ! 대신 할 수 는 각 시나리오 전에 평가 될 수 있도록.


일반적으로 let()더 좋은 구문이며 @name모든 곳에서 기호 를 입력하는 것을 저장합니다 . 그러나 주의를 기울이십시오! let()변수를 사용하려고 할 때까지 변수가 실제로 존재하지 않기 때문에 미묘한 버그 (또는 적어도 머리 긁힘) 가 있음을 발견 했습니다 ... 이야기를 들려주세요 : puts후를 추가 let()하면 변수가 올바른지 볼 수 있습니다. 그러나 puts사양이 없으면 실패합니다.이 미묘함을 발견했습니다.

또한 let()모든 상황에서 캐시되지 않는 것으로 나타났습니다 ! 내 블로그에 썼습니다 : http://technicaldebt.com/?p=1242

어쩌면 나 일까?


let은 본질적으로 Proc로 기능합니다. 또한 캐시되었습니다.

한 가지 문제는 바로 let ...으로 확인했습니다. 변경 사항을 평가하는 Spec 블록에서.

let(:object) {FactoryGirl.create :object}

expect {
  post :destroy, id: review.id
}.to change(Object, :count).by(-1)

당신은 let당신의 예상 블록 밖에서 전화해야합니다 . 즉, 당신은 FactoryGirl.create당신의 let 블록에 전화 하고 있습니다. 나는 보통 객체가 지속되는지 확인함으로써 이것을한다.

object.persisted?.should eq true

그렇지 않으면 let블록이 처음 호출 될 때 지연 인스턴스화로 인해 데이터베이스 변경이 실제로 발생합니다.

최신 정보

메모를 추가하기 만하면됩니다. 코드 골프 또는이 경우 rspec 골프를 조심하십시오 .

이 경우 객체가 응답하는 메소드를 호출하면됩니다. 따라서 _.persisted?객체 에서 _ 메소드를 진실로 호출합니다 . 내가하려는 것은 객체를 인스턴스화하는 것입니다. 당신은 빈 전화 할 수 있습니까? 또는 nil? 너무. 요점은 테스트가 아니라 개체를 호출하여 생명을 얻는 것입니다.

그래서 당신은 리팩토링 할 수 없습니다

object.persisted?.should eq true

되려고

object.should be_persisted 

객체가 인스턴스화되지 않았기 때문에 ... 게으른. :)

업데이트 2

렛을 활용하십시오 ! 이 문제를 완전히 피해야하는 인스턴트 객체 생성 구문 . 그것은 뱅킹되지 않은 let의 게으름의 많은 목적을 물리 칠 것입니다.

또한 경우에 따라 추가 옵션을 제공 할 수 있으므로 실제로는 주제 구문 을 활용하는 것이 좋습니다.

subject(:object) {FactoryGirl.create :object}

Joseph에 대한 참고 사항-데이터베이스 객체를 생성 before(:all)하는 경우 트랜잭션에서 캡처되지 않으며 테스트 데이터베이스에 균열이 생길 가능성이 훨씬 큽니다. before(:each)대신 사용하십시오 .

let과 게으른 평가를 사용해야하는 또 다른 이유는이 매우 복잡한 예제 에서처럼 컨텍스트에서 let을 재정 의하여 복잡한 객체를 가져 와서 개별 조각을 테스트 할 수 있기 때문입니다.

context "foo" do
  let(:params) do
     { :foo => foo,  :bar => "bar" }
  end
  let(:foo) { "foo" }
  it "is set to foo" do
    params[:foo].should eq("foo")
  end
  context "when foo is bar" do
    let(:foo) { "bar" }
    # NOTE we didn't have to redefine params entirely!
    it "is set to bar" do
      params[:foo].should eq("bar")
    end
  end
end

기본적으로 "이전"은을 의미합니다 before(:each). Rspec Book을 참조하십시오 (저작권 2010, 228 페이지).

before(scope = :each, options={}, &block)

"it"블록에 데이터를 작성하기 위해 메소드를 before(:each)호출 할 필요없이 각 예제 그룹에 대한 일부 데이터를 시드하는 데 사용 합니다 let. 이 경우 "it"블록의 코드가 줄어 듭니다.

let일부 예제에서는 데이터를 원하지만 다른 데이터는 원하지 않는 경우에 사용 합니다.

"it"블록을 건조시키는 데는 앞뒤가 모두 좋습니다.

혼동을 피하기 위해 "let"은와 동일하지 않습니다 before(:all). "하자"는 각 예에 대한 방법과 값을 다시 평가하지만 ( "it") 동일한 예에서 여러 호출에 걸쳐 값을 캐시합니다. https://www.relishapp.com/rspec/rspec-core/v/2-6/docs/helper-methods/let-and-let 에서 자세한 내용을 확인할 수 있습니다.


let컨텍스트를 사용하여 API 사양에서 HTTP 404 응답을 테스트 하는 데 사용합니다.

리소스를 만들려면을 사용 let!합니다. 그러나 리소스 식별자를 저장하려면을 사용 let합니다. 그것이 어떻게 생겼는지 살펴보십시오 :

let!(:country)   { create(:country) }
let(:country_id) { country.id }
before           { get "api/countries/#{country_id}" }

it 'responds with HTTP 200' { should respond_with(200) }

context 'when the country does not exist' do
  let(:country_id) { -1 }
  it 'responds with HTTP 404' { should respond_with(404) }
end

그러면 사양을 깨끗하고 읽을 수 있습니다.

참고 URL : https://stackoverflow.com/questions/5359558/when-to-use-rspec-let



도와주세요.
반응형