Created
March 15, 2017 13:03
-
-
Save guih/e113c62d7ce2968a07d23a4790ed47ab to your computer and use it in GitHub Desktop.
FloripaOnRails Meetup - TDD
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ============= | |
# What is TDD ? | |
# ============= | |
# Writing test first is not TDD, you should let your test guide your code | |
# so the test bellow should have the simplest implementation as possible | |
it 'consumes fuel' do | |
expect { drive(80) }.to change(car, :fuel).from(10).to(2) | |
end | |
# not TDD implementation | |
def drive(distance) | |
fuel_to_consume = distance / @car_effiency | |
fail "Not enough fuel" if fuel < fuel_to_consume | |
@fuel -= fuel_to_consume | |
end | |
# TDD implementation | |
def drive(distance) | |
@fuel -= 8 | |
end | |
# Then, you should write another spec that makes you change this implementation. | |
# Of couse this is the ludic version of TDD, when you got some practice, you can | |
# skip these very basic steps, but you should defenitely try the ludic one as an | |
# exercise. I can assure you that you'll be surprized how the implementation | |
# is different from the implementation without TDD. | |
# ============================= | |
# TDD tips and tricks (example) | |
# ============================= | |
RSpec.describe Car do | |
# Start declaring the subject after describe | |
# Use described_class variable | |
subject(:car) { described_class.new(parameters) } | |
let(:parameters) { {} } | |
# driver is not used in this example, I just wanted to show a FactoryGirls usage. | |
let(:driver) { FactoryGirl.build_stubbed(:driver) } | |
# Organize validations in a separated describe group | |
describe 'validations' do | |
it { is_expected.to validate_presence_of(:efficiency) } | |
it { is_expected.not_to allow_value(-1).for(:efficiency) } | |
it { is_expected.to allow_value(12).for(:efficiency) } | |
end | |
describe '#drive' do | |
# Again, start with subject after a describe block | |
subject(:drive) { car.drive(distance) } | |
let(:distance) { nil } | |
# Start with exceptions and unhappy paths | |
context 'when the car is not valid' do | |
it { is_expected.to raise_error 'Invalid car. Please check car.errors for more information' } | |
end | |
# Almost every context should have an opposite context | |
context 'when the car is valid' do | |
let(:parameters) { {efficiency: 10, fuel: 10} } | |
# Write a specification for what you're testing. | |
# For example, if you read the context and the expectations for this context, | |
# you will read: "When Car#drive when the car is valid, when the distance is | |
# above the car's current autonomy, then it consumes all the fuel and it returns | |
# the walked distance". | |
# That is totally human readable. | |
context "when the distance is above the car's current autonomy" | |
let(:distance) { 1000 } | |
it 'consumes all the fuel' do | |
is_expected.to change(car, :fuel).from(10).to(0) | |
end | |
it 'returns the walked distance' do | |
expect(drive).to eq ( 100 ) | |
end | |
end | |
context "when the distance is below the car's current autonomy" do | |
it { is_expected.to change(car, :fuel).from(10).to(2) } | |
end | |
end | |
end | |
end | |
# If your project is already a monster and you're afraid to start using TDD | |
# consider starting it with the Bugs. Whenever you're going to fix a Bug, try | |
# to write a spec for the broken scenario first, then run the spec, see it failing | |
# and only then, you should fix it and see it the spec passing. | |
# Also, you should try to start creating factories to reduce the time to setup your specs. | |
# Last but not least, "Never trust a spec you didn't see fail", it's really common to write | |
# a spec that just doesn't test anything. | |
# There's more at https://speakerdeck.com/guih |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment