Synthesis 0.0.2
George Malamidis, January 27th, 2008Synthesis version 0.0.2 was released a bit more than a week ago carrying one prominent new feature: Validation of simulated method call expectations takes into account the types of the arguments of the method’s signature.
Let’s revisit the example project from the Using Synthesis with Test::Unit and Mocha article and change the save method of the Storage class to take an additional argument – mode.
storage.rb:
class Storage
def initialize(filename)
@filename = filename
end
def save(val, mode)
File.open(@filename, mode) {|f| f << val}
end
end
We should also update the corresponding unit test.
storage_test.rb:
require "test/unit"
require "fileutils"
require File.dirname(__FILE__) + "/../lib/synthesis_example"
class StorageTest < Test::Unit::TestCase
def test_saves_to_file
Storage.new('test.txt').save('rock', 'w')
assert_equal 'rock', File.read('test.txt')
ensure
FileUtils.rm_f('test.txt')
end
end
Running storage_test.rb produces:
TW-MacBook-Pro:synthesis_example gmalamid$ ruby test/storage_test.rb Loaded suite test/storage_test Started . Finished in 0.004917 seconds. 1 tests, 1 assertions, 0 failures, 0 errors
Also, data_brander_test.rb still passes.
TW-MacBook-Pro:synthesis_example gmalamid$ ruby test/data_brander_test.rb Loaded suite test/data_brander_test Started . Finished in 0.00047 seconds. 1 tests, 1 assertions, 0 failures, 0 errors
At this point, all of the application’s tests are producing a green build, although there is an obvious bug. The signature of Storage#save has changed, so DataBrander#save_branded is broken.
With version 0.0.2, Synthesis attempts to address this issue and, indeed, invoking the test:synthesis task produces:
W-MacBook-Pro:synthesis_example gmalamid$ rake (in /Users/gmalamid/devel/ruby/whatever_code/synthesis_example) [Synthesis] Collecting expectations... Loaded suite /usr/bin/rake Started .. Finished in 0.002701 seconds. 2 tests, 2 assertions, 0 failures, 0 errors [Synthesis] Verifying expectation invocations... Loaded suite /usr/bin/rake Started .. Finished in 0.002483 seconds. 2 tests, 2 assertions, 0 failures, 0 errors [Synthesis] [Synthesis] Tested Expectations: [Synthesis] [Synthesis] Untested Expectations: [Synthesis] Storage.new.save(String) [Synthesis] [Synthesis] Ignoring: [Synthesis] [Synthesis] FAILED.
In order for the Synthesis task to be successful we need to update data_brander.rb and the corresponding test to correctly cover the interaction between DataBrander and Storage, and, conveniently, fix the associated bug.
data_brander.rb:
class DataBrander
BRAND = "METAL"
def initialize(storage)
@storage = storage
end
def save_branded(data)
@storage.save "#{BRAND} - #{data}", "w"
end
end
data_brander_test.rb:
%w(test/unit rubygems mocha).each { |l| require l }
require File.dirname(__FILE__) + "/../lib/synthesis_example"
class DataBranderTest << Test::Unit::TestCase
def test_saves_branded_to_storage
storage = Storage.new 'whatever'
storage.expects(:save).with('METAL - rock', 'w')
DataBrander.new(storage).save_branded 'rock'
end
end
This will hopefully tip the confidence scale a bit closer to the point where we feel it’s safe enough to omit having to write some functional tests that would prove the interacting members will integrate nicely when used together.
TW-MacBook-Pro:synthesis_example gmalamid$ rake (in /Users/gmalamid/devel/ruby/whatever_code/synthesis_example) [Synthesis] Collecting expectations... Loaded suite /usr/bin/rake Started .. Finished in 0.002724 seconds. 2 tests, 2 assertions, 0 failures, 0 errors [Synthesis] Verifying expectation invocations... Loaded suite /usr/bin/rake Started .. Finished in 0.002409 seconds. 2 tests, 2 assertions, 0 failures, 0 errors [Synthesis] [Synthesis] SUCCESS.
