Reputation: 34884
I have a mailer
class MyMailer < ActionMailer::Base
def send1(a, b, c)
#.....
mail(....).deliver
end
def send2(a, b, c)
#.....
mail(....).deliver
end
end
And I test it
describe MyMailer do
describe "#send1" do
let(:a) { "[email protected]" }
let(:b) { "message" }
let(:c) { FactoryGirl.create :user }
let(:send1_email1) { MyMailer.send1 a, b, c }
after(:all) { MyMailer.deliveries.clear }
it "should send an email" do
expect(MyMailer.deliveries.count).to eq(1)
end
#........ other ITs testing send1_emai1
describe "#send2" do
let(:d) { "[email protected]" }
let(:e) { FactoryGirl.create :admin }
let(:g) { "message2" }
let(:send1_emai2) { MyMailer.send2 d, e, g }
after(:all) { MyMailer.deliveries.clear }
it "should send an email2" do
expect(MyMailer.deliveries.count).to eq(1)
end
#........ other ITs testing send1_emai2
end
So most of the time it fails due to the errors should send an email expect 1 got 2 and should send an email expect 1 got 4 or 0 Sometimes the numbers are different (got 0 - 4). I tried to do this:
let!(:send1_email) { MyMailer.send1 a, b, c }
let!(:send1_emai2) { MyMailer.send2 d, e, g }
But it also failed.
Failure/Error: expect(MyMailer.deliveries.count).to eq(1)
expected: 1
got: 4
I wonder why?
Previously I used before :all
and @variables
and everything was well (no errors)
The same errors:
it "should send an email" do
expect(MyMailer.deliveries.count).to eq(1)
MyMailer.deliveries.clear
end
it "should send an email2" do
expect(MyMailer.deliveries.count).to eq(1)
MyMailer.deliveries.clear
end
Upvotes: 1
Views: 131
Reputation: 13181
There is a difference between let
and let!
let
is instantiated only when called, in other words, rspec won't be looking inside let
block before you use the variable.
let(:send1_email2) { MyMailer.send2 d, e, g }
it 'testing' do
# email not sent yet because we use let without bang
expect(MyMailer.deliveries.count).to eq(0)
send1_email2.call_a_method
# now email is sent since we used the variable send1_email2
expect(MyMailer.deliveries.count).to eq(1)
end
let!
is instantiated as if it was a before
block
let!(:send1_email2) { MyMailer.send2 d, e, g }
it 'testing' do
# before we do anything the email is sent because we used let with a bang
expect(MyMailer.deliveries.count).to eq(1)
end
Additionaly do no user after(:all) { MyMailer.deliveries.clear }
, but after { MyMailer.deliveries.clear }
instead, otherwise your counter won't be cleared between your examples
Upvotes: 2
Reputation: 1761
As the documentation states at this location.
Use let to define a memoized helper method. The value will be cached across multiple calls in the same example but not across examples.
Also i'm sure you are aware that rspec runs examples in random order, meaning other examples call the mail-sending let() helper, meaning by the time it gets to your test, the suite has already sent out 4 emails, making your test fail. You should not rely on the order of defining tests. You should be making sure that your test data is scrubbed and cleaned before your examples.
Upvotes: 2