Test driven development is the art of writing test code that you run that runs a bit of your production code to ensure that your production code does what you thought your production code would do when you were writing the test code.
... before that bit of production code even exists.
Writing code that expresses an intention
... then making that intention a reality.
Integration testsUnit tests
Several theories:
It will not make your code have less bugs...
... by definition, you are writing more code - therefore you might have more bugs.
... but it might help you catch them quicker.
... and it might help you ship fewer bugs.
It will not provide rigorous proof that your code works...
... but it might alert you when new features break existing code.
... and may encourage you to write more maintainable code.
It will not make your code easier to read or maintain...
... only you can do that.
... but it can give you hints, if you're listening for them.
... and it can be used as a secondary form of documentation.
Class: SetTestCase
superclass: TestCase
instance variables: empty full
SetTestCase>>setUp
empty := Set new.
full := Set
with: #abc
with: 5
SetTestCase>>testAdd
empty add: 5.
self should: [empty includes: 5]
(Kent Beck's original paper on Testing in Smalltalk)
class SetTestCase < TestCase
def setup
@empty = []
@full = ['abc', 5]
end
def test_add
@empty << 5
should(@empty.include? 5)
end
end
require 'minitest/autorun' # found in ruby 1.9's standard library
class ArrayTestCase < MiniTest::Unit::TestCase # A little more verbose
def setup
@empty = []
@full = ['abc', 5]
end
def test_add
@empty << 5
assert(@empty.include? 5)
end
end
require 'test_helper'
class ArrayTestCase < ActiveSupport::TestCase # inherits from MiniTest::Unit::TestCase
def setup
@empty = []
@full = ['abc', 5]
end
def test_add
@empty << 5
assert(@empty.include? 5)
end
end
require 'test_helper'
class ArrayTestCase < ActiveSupport::TestCase
setup do
@empty = []
@full = ['abc', 5]
end
test 'should add items to empty arrays' do
@empty << 5
assert(@empty.include? 5)
end
end
MiniTest has a "spec" syntax too.
I would highly recommend trying it - it takes the readability further, but it does require a little more setup.
https://github.com/metaskills/minitest-spec-rails
Also, you might want to look at RSpec - we might do another presentation on this later
Run options: --seed 41230 # Running tests: . Finished tests in 0.092020s, 10.8672 tests/s, 10.8672 assertions/s. 1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
If I make a mistake in the above code, this is what I might get:
1) Failure: EventTest#test_should_add_the_number_5_to_the_array [/Users/matthew/projects/clients/nrug/nrug/test/models/event_test.rb:10]: Failed assertion, no message given.
If I use wrong, I get this message instead:
1) Error: EventTest#test_should_add_the_number_5_to_the_array: Wrong::Assert::AssertionFailedError: Expected @empty.include?(6), but @empty is [5] test/models/event_test.rb:10:in `block in <class:EventTest>'
require 'test_helper'
class ArrayTestCase < ActiveSupport::TestCase
setup do
@empty = []
@full = ['abc', 5]
end
test 'should add items to empty arrays' do
@empty << 5
assert { @empty.include? 6 }
end
end
This will run your assert twice.
Open your Gemfile
Add the following line:
gem "wrong"
On the command line, run
bundle install
Lastly, in your test_helper.rb file, add the following lines
# At the end of your requires:
require 'wrong'
# Then, after `class ActiveSupport::TestCase`
include Wrong
From the commandline, to run all tests:
rake test
To run all tests in a particular file:
rake test test/models/event_test.rb
To run a particular test:
rake test test/models/event_test.rb test_that_something_happens
Alternatively, autotest! (autotest-rails, autotest-growl)
Rails may have already provided you tests
... you might need to delete the fixture files. Don't worry, we won't be using them.
Models are a good place to start:
require 'test_helper'
class EventTest < ActiveSupport::TestCase
setup do
@event = Event.new(
:title => "NRUG Episode II - Attack of the rubyists",
:description => "They're coming! " * 100,
:date => Date.today,
:time => Time.now,
)
end
test 'should present the date in a pretty manner' do
@event.date = Date.parse "2013-10-15"
assert { @event.pretty_date == "Tuesday 17 December 2013" }
end
end
You should see red:
# Running tests: E Finished tests in 0.116580s, 8.5778 tests/s, 0.0000 assertions/s. 1) Error: EventTest#test_should_present_the_date_in_a_pretty_manner: NoMethodError: undefined method `pretty_date' for #<Event:0x007fc440684230> test/models/event_test.rb:15:in `block (2 levels) in <class:EventTest>' test/models/event_test.rb:15:in `block in <class:EventTest>'
class Event < ActiveRecord::Base
# ... normal model gumpf ...
def pretty_date
date.strftime('%A %-d %B %Y')
end
end
You should STILL see red:
# Running tests: E Finished tests in 0.046519s, 21.4966 tests/s, 0.0000 assertions/s. 1) Error: EventTest#test_should_present_the_date_in_a_pretty_manner: Wrong::Assert::AssertionFailedError: Expected (@event.pretty_date == "Tuesday 17 December 2013"), but Strings differ at position 9: first: "Tuesday 15 October 2013" second: "Tuesday 17 December 2013" @event.pretty_date is "Tuesday 15 October 2013" @event is #<Event id: nil, date: "2013-10-15", time: "2013-10-15 18:40:13", location: nil, title: "NRUG Episode II - Attack of the rubyists", event_description: nil&rt; test/models/event_test.rb:15:in `block in <class:EventTest&rt;'
Thankfully, wrong has told us what was wrong...
require 'test_helper'
class EventTest < ActiveSupport::TestCase
setup do
@event = Event.new(
:title => "NRUG Episode II - Attack of the rubyists",
:description => "They're coming! " * 100,
:date => Date.today,
:time => Time.now,
)
end
test 'should present the date in a pretty manner' do
@event.date = Date.parse "2013-10-15"
assert { @event.pretty_date == "Tuesday 15 October 2013" }
end
end
All the links in this presentation, plus:
Code will be made available after the show