Qual é a diferença entre let
e um before
bloco em RSpec?
E quando usar cada um?
Qual será a boa abordagem (let ou before) no exemplo abaixo?
let(:user) { User.make !}
let(:account) {user.account.make!}
before(:each) do
@user = User.make!
@account = @user.account.make!
end
Eu estudei este post stackoverflow
Mas é bom definir coisas como deixar para associação como acima?
ruby-on-rails
unit-testing
rspec
Kriysna
fonte
fonte
Respostas:
As pessoas parecem ter explicado algumas das maneiras básicas em que diferem, mas as omitiram
before(:all)
e não explicam exatamente por que deveriam ser usadas.É minha convicção que variáveis de instância não têm lugar sendo usadas na grande maioria das especificações, em parte devido aos motivos mencionados nesta resposta , então não vou mencioná-los como uma opção aqui.
deixe os blocos
O código dentro de um
let
bloco só é executado quando referenciado, o carregamento lento significa que a ordem desses blocos é irrelevante. Isso lhe dá uma grande quantidade de energia para reduzir a configuração repetida por meio de suas especificações.Um exemplo (extremamente pequeno e artificial) disso é:
Você pode ver que
has_moustache
é definido de forma diferente em cada caso, mas não há necessidade de repetir asubject
definição. Algo importante notar é quelet
será utilizado o último bloco definido no contexto atual. Isso é bom para definir um padrão a ser usado para a maioria das especificações, que podem ser substituídas se necessário.Por exemplo, verificar o valor de retorno de
calculate_awesome
se passado umperson
modelo comtop_hat
definido como verdadeiro, mas sem bigode seria:Outra coisa a se notar sobre os blocos let, eles não devem ser usados se você estiver procurando por algo que foi salvo no banco de dados (ou seja
Library.find_awesome_people(search_criteria)
), pois eles não serão salvos no banco de dados a menos que já tenham sido referenciados.let!
oubefore
blocos são o que deve ser usado aqui.Além disso, nunca mais nunca usar
before
a execução do gatilho delet
blocos, isso é o quelet!
é feito para!deixei! blocos
let!
os blocos são executados na ordem em que são definidos (como um bloco anterior). A única diferença principal em relação aos blocos anteriores é que você obtém uma referência explícita a essa variável, em vez de precisar recorrer a variáveis de instância.Tal como acontece com os
let
blocos, se várioslet!
blocos forem definidos com o mesmo nome, o mais recente é o que será usado na execução. A principal diferença é que oslet!
blocos serão executados várias vezes se usados dessa forma, enquanto olet
bloco será executado apenas na última vez.antes (: cada) dos blocos
before(:each)
é o padrão antes do bloco e, portanto, pode ser referenciado como embefore {}
vez de especificar o completo abefore(:each) {}
cada vez.É minha preferência pessoal usar
before
blocos em algumas situações básicas. Vou usar blocos antes se:before { get :index }
). Mesmo que você possa usarsubject
para isso em muitos casos, às vezes parece mais explícito se você não precisar de uma referência.Se você estiver escrevendo grandes
before
blocos para suas especificações, verifique suas fábricas e certifique-se de compreender totalmente as características e sua flexibilidade.blocos antes (: todos)
Eles são executados apenas uma vez, antes das especificações no contexto atual (e seus filhos). Eles podem ser usados com grande vantagem se escritos corretamente, pois há certas situações que podem reduzir a execução e o esforço.
Um exemplo (que dificilmente afetaria o tempo de execução) é simular uma variável ENV para um teste, o que você só deve precisar fazer uma vez.
Espero que ajude :)
fonte
before(:all)
opção não existe no Minitest. Aqui estão algumas soluções alternativas nos comentários: github.com/seattlerb/minitest/issues/61its
não está mais no rspec-core. Uma forma mais moderna e idiomática éit { is_expected.to be_awesome }
.Quase sempre, eu prefiro
let
. A postagem que você vincula especifica quelet
também é mais rápido. No entanto, às vezes, quando muitos comandos precisam ser executados, eu poderia usarbefore(:each)
porque sua sintaxe é mais clara quando muitos comandos estão envolvidos.Em seu exemplo, eu definitivamente preferiria usar em
let
vez debefore(:each)
. De modo geral, quando apenas algumas inicializações de variáveis são feitas, eu costumo gostar de usarlet
.fonte
Uma grande diferença que não foi mencionada é que as variáveis definidas com
let
não são instanciadas até que você as chame pela primeira vez. Portanto, embora umbefore(:each)
bloco instancie todas as variáveis,let
vamos definir várias variáveis que você pode usar em vários testes, ele não as instancia automaticamente. Sem saber disso, seus testes podem voltar a se incomodar se você espera que todos os dados sejam carregados com antecedência. Em alguns casos, você pode até querer definir uma série delet
variáveis e, em seguida, usar umbefore(:each)
bloco para chamar cadalet
instância apenas para ter certeza de que os dados estão disponíveis para começar.fonte
let!
para definir métodos que são chamados antes de cada exemplo. Veja os documentos RSpec .Parece que você está usando o Machinist. Cuidado, você pode ver alguns problemas com o make! dentro de let (a versão non-bang) acontecendo fora da transação global de fixture (se você estiver usando fixtures transacionais também), corrompendo os dados para seus outros testes.
fonte