Synthesis 0.0.2
Synthesis 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.