RSpec : let과 before 블록의 차이점은 무엇입니까?

lottogame 2020. 9. 11. 19:27

RSpec : let과 before 블록의 차이점은 무엇입니까?

RSpec에서 letbefore블록의 차이점은 무엇입니까 ?

그리고 언제 각각을 사용합니까?

아래 예에서 좋은 접근 방식 (let 또는 before)은 무엇입니까?

let(:user) { User.make !}
let(:account) {user.account.make!}

before(:each) do
 @user = User.make!
 @account = @user.account.make!

stackoverflow 게시물을 연구했습니다.

그러나 위와 같은 연관성에 대해 let을 정의하는 것이 좋은가요?

사람들은 서로 다른 몇 가지 기본적인 방법을 before(:all)설명 했지만 생략했고 왜 사용해야하는지 정확히 설명하지 않았습니다.

인스턴스 변수는 부분적 으로이 답변에 언급 된 이유 때문에 대부분의 사양에서 사용되는 곳이 없다고 생각 하므로 여기에서 옵션으로 언급하지 않겠습니다.


let블록 내의 코드 는 참조 될 때만 실행되며 지연로드는 이러한 블록의 순서가 관련이 없음을 의미합니다. 이렇게하면 사양을 통해 반복되는 설정을 줄일 수있는 많은 전력이 제공됩니다.

이에 대한 한 가지 (매우 작고 인위적인) 예는 다음과 같습니다.

let(:person)     { build(:person) }
subject(:result) { Library.calculate_awesome(person, has_moustache) }

context 'with a moustache' do
  let(:has_moustache) { true } 
  its(:awesome?)      { should be_true }

context 'without a moustache' do
  let(:has_moustache) { false } 
  its(:awesome?)      { should be_false }

has_moustache각 경우에 다르게 정의되어 있음을 알 수 있지만 subject정의 를 반복 할 필요는 없습니다 . 주목해야 할 점은 let현재 컨텍스트에 정의 된 마지막 블록이 사용된다는 것입니다. 이는 대부분의 사양에 사용할 기본값을 설정하는 데 유용하며 필요한 경우 덮어 쓸 수 있습니다.

예를 들어, true 설정된 모델을 calculate_awesome전달 했지만 콧수염은없는 경우 의 반환 값을 확인하면 다음 persontop_hat같습니다.

context 'without a moustache but with a top hat' do
  let(:has_moustache) { false } 
  let(:person)        { build(:person, top_hat: true) }
  its(:awesome?)      { should be_true }

Another thing to note about let blocks, they should not be used if you're searching for something which has been saved to the database (i.e. Library.find_awesome_people(search_criteria)) as they will not be saved to the database unless they have already been referenced. let! or before blocks are what should be used here.

Also, never ever use before to trigger execution of let blocks, this is what let! is made for!

let! blocks

let! blocks are executed in the order they are defined (much like a before block). The one core difference to before blocks is that you get an explicit reference to this variable, rather than needing to fall back to instance variables.

As with let blocks, if multiple let! blocks are defined with the same name, the most recent is what will be used in execution. The core difference being that let! blocks will be executed multiple times if used like this, whereas the let block will only execute the last time.

before(:each) blocks

before(:each) is the default before block, and can therefore be referenced as before {} rather than specifying the full before(:each) {} each time.

It's my personal preference to use before blocks in a few core situations. I will use before blocks if:

  • I'm using mocking, stubbing or doubles
  • There is any reasonable sized setup (generally this is a sign your factory traits haven't been setup correctly)
  • There's a number of variables which I don't need to reference directly, but are required for setup
  • I'm writing functional controller tests in rails, and I want to execute a specific request to test (i.e. before { get :index }). Even though you could use subject for this in a lot of cases, it sometimes feels more explicit if you don't require a reference.

If you find yourself writing large before blocks for your specs, check your factories and make sure you fully understand traits and their flexibility.

before(:all) blocks

These are only ever executed once, before the specs in the current context (and its children). These can be used to great advantage if written correctly, as there are certain situations this can cut down on execution and effort.

One example (which would hardly affect execution time at all) is mocking out an ENV variable for a test, which you should only ever need to do once.

Hope that helps :)

Almost always, I prefer let. The post that you link specifies that let is also faster. However, at times, when many commands have to be executed, I could use before(:each) because its syntax is more clear when many commands are involved.

In your example, I would definitely prefer to use let instead of before(:each). Generally speaking, when just some variable initialization is done, I tend to like using let.

A big difference that hasn't been mentioned is that variables defined with let don't get instantiated until you call it the first time. So while a before(:each) block would instantiate all of the variables, let let's you define a number of variables you might use across multiple tests, it doesn't automatically instantiate them. Without knowing this, your tests could come back to bite yourself if you're expecting all of the data to be loaded beforehand. In some cases, you may even want to define a number of let variables, then use a before(:each) block to call each let instance just to make sure the data is available to begin with.

It looks like you are using Machinist. Beware, you may see some issues with make! inside of let (the non-bang version) happening outside of the global fixture transaction (if you are using transactional fixtures as well) so corrupting the data for your other tests.

참고URL :