Our first test
describe User do
subject(:user) do
User.new(first_name: 'John', last_name: 'Doe')
end
describe '#full_name' do
it 'has correct full name' do
expect(user.full_name).to eq('John Doe')
end
end
end
`subject`
subject(:user) do
User.new(first_name: 'John', last_name: 'Doe')
end
describe '#full_name' do
subject(:full_name) { user.full_name } # !
it { is_expected.to eq 'John Doe' }
end
`let`
subject(:user) do
User.new(first_name: first_name, last_name: last_name) # !
end
let(:first_name) { 'John' } # !
let(:last_name) { 'Doe' } # !
describe '#full_name' do
subject(:full_name) { user.full_name }
it { is_expected.to eq 'John Doe' }
end
`context`
# ...
describe '#full_name' do
subject(:full_name) { user.full_name }
context 'when last name is missing' do # !
let(:last_name) { nil }
it { is_expected.to eq 'John' }
end
context 'when first and last name are given' do # !
it { is_expected.to eq 'John Doe' }
end
end
Lets code little more!
class User
# ...
def friends_count
FacebookApi.get('friends_count')
end
end
`before`
# ...
describe '#friends_count' do
before do
allow(FacebookApi).to receive(:get).and_return(5)
end
it 'returns correct friends number' do
expect(user.friends_count).to eq 5
end
end
`allow` (stub)
# ...
describe '#friends_count' do
before do
allow(FacebookApi).to receive(:get).and_return(5) # !
end
it 'makes facebook request' do
user.friends_count
expect(FacebookApi).to have_received(:get)
end
end
`expect` (mock)
# ...
describe '#friends_count' do
it 'makes facebook request' do
expect(FacebookApi).to receive(:get).and_return(5) # !
user.friends_count
end
end
Lets code a little bit
class User < ActiveRecord::Base
validates :name, length: { minimum: 5 }
validates :email, format: { with: /\w@\w/ }
# ...
end
RSpec.describe User do
subject(:user) { user.new(email: email, name: name) }
let(:email) { 'john@example.com' }
let(:name) { 'john' }
end
Rule #1
it 'has valid length' do
expect(User).to validate_length_of(:name).is_at_least(5)
end
Rule #1
Trust yourself. Do not test existence of code
Rule #2
describe '#valid?' do
subject(:is_valid) { user.valid? }
context 'when name is short' do
let(:name) { 'j' }
it { is_expected.to be false} # better. still not good. Why?
end
context 'when email is incorrect' do
let(:email) { 'e@@m.zz' }
it { is_expected.to be false } # good. Why?
end
end
Rule #2
Trust your gems test coverage. Do not test logic of your gems
Rule #3
class User
MAX_FRIENDS_COUNT = 100
def non_friends_count
MAX_FRIENDS_COUNT - friends_count
end
end
describe '#non_friends_count' do
before { allow(user).to receive(:friends_count) { 10 } }
it 'returns correct number' do
expect(user.non_friends_count).to eq 90 # good
expect(user).to have_received(:friends_count) # bad
end
end
Rule #3
Test business logic
Rule #4
Always test your code
TL;DR;
test public methods written by you