RSpec : let과 before 블록의 차이점은 무엇입니까?
RSpec에서 let
와 before
블록의 차이점은 무엇입니까 ?
그리고 언제 각각을 사용합니까?
아래 예에서 좋은 접근 방식 (let 또는 before)은 무엇입니까?
let(:user) { User.make !}
let(:account) {user.account.make!}
before(:each) do
@user = User.make!
@account = @user.account.make!
end
이 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 }
end
context 'without a moustache' do
let(:has_moustache) { false }
its(:awesome?) { should be_false }
end
has_moustache
각 경우에 다르게 정의되어 있음을 알 수 있지만 subject
정의 를 반복 할 필요는 없습니다 . 주목해야 할 점은 let
현재 컨텍스트에 정의 된 마지막 블록이 사용된다는 것입니다. 이는 대부분의 사양에 사용할 기본값을 설정하는 데 유용하며 필요한 경우 덮어 쓸 수 있습니다.
예를 들어, true 로 설정된 모델을 calculate_awesome
전달 했지만 콧수염은없는 경우 의 반환 값을 확인하면 다음 person
과 top_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 }
end
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 usesubject
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.
'Programing' 카테고리의 다른 글
IPv6 앱 스토어 거부 (0) | 2020.09.12 |
---|---|
DownloadManager를 사용하여 활동 내에서 다운로드 진행률 표시 (0) | 2020.09.12 |
특정 태그가있는 Docker 이미지가 로컬에 있는지 확인하는 방법은 무엇입니까? (0) | 2020.09.11 |
Reactjs의 새로운 react-router-dom에서 Redirect를 사용하는 방법 (0) | 2020.09.11 |
Perl의 프린트는 어떻게 기본적으로 개행을 추가 할 수 있습니까? (0) | 2020.09.11 |