Unit testing

The path from coffee to confidence

David Faulkenberry

CS 320 Geek Talk

April 24th, 2017

HTTP - Hypertext Transfer Protocol

Did you know?...

HTTP - Hypertext Transfer Protocol

April 1st, 1998 - IETF RFC 2324

Hyper

Text

Coffee

Pot

Control

Protocol

Did you know?...

January 5th, 2016 - Amazon.com

Test-driven development (TDD)

Define an expectation of your system

Minimally satisfy the expectation

Evaluate and introduce new expectations as needed

#spec/models/coffee_pot_spec.rb
describe CoffeePot do
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  it 'needs coffee grounds and water to be ready'
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }

  it 'needs coffee grounds and water to be ready'
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
  end
end
uninitialized constant CoffeePot (NameError)
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
  end
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base
end
expected #<CoffeePot ...> to respond to `ready?`
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def ready?
  end
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def ready?
    has_coffee_grounds? && has_water?
  end
end
undefined method `has_coffee_grounds?`
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def ready?
    has_coffee_grounds? && has_water?
  end
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def has_coffee_grounds?
  end

  def ready?
    has_coffee_grounds? && has_water?
  end
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def has_coffee_grounds?
    false
  end

  def ready?
    has_coffee_grounds? && has_water?
  end
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def has_coffee_grounds?
    false
  end

  def has_water?
    false
  end

  def ready?
    has_coffee_grounds? && has_water?
  end
end
1 example, 0 failures
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def has_coffee_grounds?
    false
  end

  def has_water?
    false
  end

  def ready?
    has_coffee_grounds? && has_water?
  end
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }
  let(:full_pot) { create :coffee_pot }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def has_coffee_grounds?
    false
  end

  def has_water?
    false
  end

  def ready?
    has_coffee_grounds? && has_water?
  end
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }
  let(:full_pot) { create :coffee_pot, coffee_grounds: 8.0 }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def has_coffee_grounds?
    false
  end

  def has_water?
    false
  end

  def ready?
    has_coffee_grounds? && has_water?
  end
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }
  let(:full_pot) { create :coffee_pot, coffee_grounds: 8.0, water: 10.0 }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def has_coffee_grounds?
    false
  end

  def has_water?
    false
  end

  def ready?
    has_coffee_grounds? && has_water?
  end
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }
  let(:full_pot) { create :coffee_pot, coffee_grounds: 8.0, water: 10.0 }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
    expect(full_pot)
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def has_coffee_grounds?
    false
  end

  def has_water?
    false
  end

  def ready?
    has_coffee_grounds? && has_water?
  end
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }
  let(:full_pot) { create :coffee_pot, coffee_grounds: 8.0, water: 10.0 }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
    expect(full_pot).to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def has_coffee_grounds?
    false
  end

  def has_water?
    false
  end

  def ready?
    has_coffee_grounds? && has_water?
  end
end
expected `#<CoffeePot ...>.ready?` to return true, got false
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }
  let(:full_pot) { create :coffee_pot, coffee_grounds: 8.0, water: 10.0 }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
    expect(full_pot).to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def has_coffee_grounds?
    false
  end

  def has_water?
    false
  end

  def ready?
    has_coffee_grounds? && has_water?
  end
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }
  let(:full_pot) { create :coffee_pot, coffee_grounds: 8.0, water: 10.0 }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
    expect(full_pot).to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def has_coffee_grounds?
    coffee_grounds > 0
  end

  def has_water?
    false
  end

  def ready?
    has_coffee_grounds? && has_water?
  end
end
#spec/models/coffee_pot_spec.rb
describe CoffeePot do
  let(:empty_pot) { create :coffee_pot }
  let(:full_pot) { create :coffee_pot, coffee_grounds: 8.0, water: 10.0 }

  it 'needs coffee grounds and water to be ready' do
    expect(empty_pot).not_to be_ready
    expect(full_pot).to be_ready
  end
end

#app/models/coffee_pot.rb
class CoffeePot < ActiveRecord::Base

  def has_coffee_grounds?
    coffee_grounds > 0
  end

  def has_water?
    water > 0
  end

  def ready?
    has_coffee_grounds? && has_water?
  end
end
1 example, 0 failures

Test-driven development (TDD)

Define an expectation of your system

Minimally satisfy the expectation

Evaluate and introduce new expectations as needed

https://github.com/umts/jobapps

Travis CI

Continuous

Integration

Travis CI

Continuous

Integration

Simplecov

CodeClimate

CodeClimate

app/models/application_record.rb:88:4: C: Trailing whitespace detected.
     end
        ^
app/models/application_record.rb:63:6: C: Inconsistent indentation detected.
     all_genders = GENDER_OPTIONS | gender_records.pluck(:gender)
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/models/application_record.rb:6:25: C: Use the new Ruby 1.9 hash syntax.
    delegate :department, :to => :position
                          ^^^^^^
app/models/application_record.rb:62:27: C: Use find_each instead of each.
     ApplicationRecord.all.each(&:add_data_types)
                           ^^^^

Rubocop

Before TDD:

"My code seems to do what I want."

Now:

Before TDD:

"My code seems to do what I want."

Now:

It follows community-accepted Ruby and Rails style conventions.

My tests account for the conditional branches in my code.

All of the tools I used to develop my code are 100% free.

The expected behavior of my code is clearly outlined in my tests.

I can prove that my code does what I want.

Before TDD:

"My code seems to do what I want."

Now:

It follows community-accepted Ruby and Rails style conventions.

My tests account for the conditional branches in my code.

All of the tools I used to develop my code are 100% free.

The expected behavior of my code is clearly outlined in my tests.

I can prove that my code does what I want.

Unit testing, take 2

By David Faulkenberry

Unit testing, take 2

CS 320 Geek Talk, April 24th, 2017

  • 1,037