handoff 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,10 @@
1
+ Handoff provides a fluent interface for testing simple delegation. The Ruby
2
+ stdlib module +Forwardable+ makes implementing delegation simple and readable.
3
+ Handoff is intended to make the code to test it just as simple and
4
+ readable.
5
+
6
+ Handoff depends on Mocha and Stubba (http://mocha.rubyforge.org/).
7
+
8
+ Here's example_test.rb to give you an idea of what your tests will look like:
9
+
10
+ :include: test/example_test.rb
@@ -0,0 +1,20 @@
1
+ module Handoff
2
+ =begin rdoc
3
+ Module mixed into a *args array to munge it into a hash keying delegating
4
+ method names to target method names.
5
+ =end
6
+ module ArgumentNormalizer
7
+
8
+ def to_method_map
9
+ return self.first if self.size == 1 && self.first.is_a?(Hash)
10
+ to_self_referencing_hash
11
+ end
12
+
13
+ def to_self_referencing_hash
14
+ hash = Hash.new
15
+ self.each {|sym| hash[sym]=sym}
16
+ hash
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,70 @@
1
+ require 'handoff/argument_normalizer'
2
+
3
+ module Handoff
4
+ # This is where the fluent stuff is.
5
+ # Get an assertion by calling Handoff#assert_handoff. Specify the delegating
6
+ # behavior with from or from_any, to, and for_method or for_methods.
7
+ class Assertion
8
+
9
+ attr_reader :method_map
10
+ attr_reader :object_under_test
11
+ private :method_map, :object_under_test
12
+
13
+ # Creates an expectation on the mock delegate that it will be touched later
14
+ # to give a failure if the user forgets to specify everything required.
15
+ def initialize mock_delegate
16
+ @mock_delegate = mock_delegate
17
+ @mock_delegate.expects(:called!)
18
+ end
19
+
20
+ # Creates an instance of +class_under_test+ with no arguments and uses it
21
+ # as the object under test.
22
+ def from_any class_under_test
23
+ from(class_under_test.new)
24
+ end
25
+
26
+ # Specifies the object being tested, returning self.
27
+ def from object_under_test
28
+ @object_under_test = object_under_test
29
+ self
30
+ end
31
+
32
+ # Specifies the accessor the object under test will use to acquire its delegate,
33
+ # returning self.
34
+ def to(delegate_accessor)
35
+ @object_under_test.expects(delegate_accessor).at_least_once.returns(@mock_delegate)
36
+ self
37
+ end
38
+
39
+ # Tells the assertion what delegating methods to test and what methods in the delegate
40
+ # they should delegate to. Then actually does the testing.
41
+ #
42
+ # :call-seq: for_methods(:delegating_method1, :delegating_method2, ...)
43
+ # for_methods({:delegating_method1 => :target_method1, :delegating_method2 => :target_method2})
44
+ #
45
+ # +args+:: symbols representing the delegating methods if they are not renamed, or
46
+ # a Hash mapping methods in the delegating class to methods in the delegate.
47
+ def for_methods(*args)
48
+ @method_map = args.extend(ArgumentNormalizer).to_method_map
49
+ conduct
50
+ end
51
+ alias for_method for_methods
52
+
53
+ private
54
+ def conduct
55
+ @mock_delegate.called!
56
+ expected_returns = {}
57
+ method_map.each_pair do |delegating_method, target|
58
+ expected_returns[delegating_method] = "#{delegating_method.to_s}_return"
59
+ @mock_delegate.expects(target).returns(expected_returns[delegating_method])
60
+ end
61
+ method_map.each_pair do |delegating_method, target|
62
+ actual = object_under_test.send(delegating_method)
63
+ unless actual.equal? expected_returns[delegating_method]
64
+ raise "expected #{delegating_method.to_s} to return #{expected_returns[method]}, but was #{actual}"
65
+ end
66
+ end
67
+ end
68
+
69
+ end
70
+ end
data/lib/handoff.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'handoff/assertion'
2
+ require 'test/unit'
3
+
4
+ # +require+ (or +require_gem+) 'handoff' and #assert_handoff can
5
+ # be called from any +Test::Unit::TestCase+ test method to create
6
+ # a new Handoff::Assertion.
7
+ #
8
+ # After defining Handoff, This file includes it in Test::Unit::TestCase.
9
+ module Handoff
10
+
11
+ # Creates an Assertion, handing a it a mock named 'handoff delegate' on which
12
+ # expectations will be set.
13
+ def assert_handoff
14
+ Handoff::Assertion.new(self.mock('handoff delegate'))
15
+ end
16
+ end
17
+
18
+ Test::Unit::TestCase.send :include, Handoff
@@ -0,0 +1,41 @@
1
+ # This example is only helpful if you're familiar with Forwardable from the
2
+ # stdlib, which you should be if you're coding delegating behavior in Ruby.
3
+ # Here comes an example of something you might have in your code base, but
4
+ # haven't managed to test readably. You might have some code like this that's
5
+ # tested in very long methods which either repeat but varying set-ups
6
+ # Foo is a simple delegating class, which normally wouldn't live in
7
+ # your test.
8
+ class Foo
9
+ require 'forwardable'
10
+ extend Forwardable
11
+ def_delegators :bar, :baz, :bat
12
+ def_delegator :bar, :baq, :bar_baq
13
+ def_delegator :bar, :ban, :bar_ban
14
+ def bar
15
+ @bar ||= BarFactory.create_for(Foo) # gets the delegate ... this is not what we're testing
16
+ end
17
+ end
18
+
19
+ require 'test/unit'
20
+ require 'rubygems'
21
+
22
+ require File.dirname(__FILE__) + '/../lib/handoff' # I require it this way because I don't want the installed gem.
23
+ # require 'handoff' # this is how you'd require handoff (or do require_gem w/ a version).
24
+
25
+ require 'mocha' # you need to require mocha and stubba in your test
26
+ require 'stubba' # ditto
27
+
28
+ class ExampleTest < Test::Unit::TestCase
29
+
30
+ def test_using_from_and_single_method
31
+ assert_handoff.from(Foo.new).to(:bar).for_method(:baz)
32
+ end
33
+
34
+ def test_using_from_any_and_multiple_methods
35
+ assert_handoff.from_any(Foo).to(:bar).for_methods(:baz, :bat)
36
+ end
37
+
38
+ def test_showing_delegating_methods_with_names_different_than_their_delegate_methods
39
+ assert_handoff.from(Foo.new).to(:bar).for_methods(:bar_baq => :baq, :bar_ban => :ban)
40
+ end
41
+ end
@@ -0,0 +1,23 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../../lib/handoff/argument_normalizer'
3
+
4
+ module Handoff
5
+ class ArgumentNormalizerTest < Test::Unit::TestCase
6
+
7
+ def test_should_return_hash_at_front_of_one_element_array
8
+ hash = {}
9
+ assert_same hash, [hash].extend(ArgumentNormalizer).to_method_map
10
+ end
11
+
12
+ def test_should_return_self_referencing_hash_for_array_of_symbols
13
+ args = [:bar, :foo].extend(ArgumentNormalizer)
14
+ assert_equal({:foo => :foo, :bar => :bar}, args.to_method_map)
15
+ end
16
+
17
+ def test_should_return_self_referencing_hash_for_one_element_array_with_symbol
18
+ args = [:foo].extend(ArgumentNormalizer)
19
+ assert_equal({:foo => :foo}, args.to_method_map)
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,40 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../test_helper'
3
+ require File.dirname(__FILE__) + '/../../lib/handoff/assertion'
4
+ require 'rubygems'
5
+ require 'mocha'
6
+ require 'stubba'
7
+
8
+ module Handoff
9
+ class AssertionTest < Test::Unit::TestCase
10
+
11
+ test 'should construct instance to test and return self when from_any is called' do
12
+ mock_class = mock(:new => nil)
13
+ mock_delegate = mock
14
+ assertion = Assertion.new(mock_delegate)
15
+ mock_delegate.expectations.clear
16
+ assert_same assertion, assertion.from_any(mock_class)
17
+ end
18
+
19
+ test 'should create expectation on creation to guard against incomplete usage' do
20
+ mock_delegate = mock
21
+ Assertion.new(mock_delegate)
22
+ assert_equal :called!, mock_delegate.expectations.first.method_name
23
+ mock_delegate.expectations.clear
24
+ end
25
+
26
+ test 'should create expectations on mock_delegate and object under test once fully specified' do
27
+ cut = define_class(Object, <<-EOS)
28
+ extend Forwardable
29
+ def_delegator :asdf, :meth
30
+ attr_reader :asdf
31
+ EOS
32
+ mock_delegate = mock
33
+ object_under_test = cut.new
34
+ Assertion.new(mock_delegate).from(object_under_test).to(:asdf).for_method(:meth)
35
+ assert_equal :asdf, object_under_test.mocha.expectations.first.method_name
36
+ assert_equal :meth, mock_delegate.expectations.last.method_name
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+ require 'rubygems'
3
+ require 'mocha'
4
+ require 'stubba'
5
+ require File.dirname(__FILE__) + '/../lib/handoff'
6
+
7
+ class HandoffTest < Test::Unit::TestCase
8
+ test 'should create a mock named "handoff delegate" and hand it to a new Assertion' do
9
+ given_name = nil
10
+ def self.mock name
11
+ assert_equal 'handoff delegate', name
12
+ :mock_return
13
+ end
14
+ Assertion.expects(:new).with(:mock_return).returns(:new_assertion)
15
+ assert_equal :new_assertion, assert_handoff
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0
3
+ specification_version: 1
4
+ name: handoff
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2007-01-17 00:00:00 -05:00
8
+ summary: Handoff is a fluent interface for making test assertions about simple delegation.
9
+ require_paths:
10
+ - lib
11
+ email: ""
12
+ homepage: http://handoff.rubyforge.org/
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: hand_off
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - John Hume
31
+ files:
32
+ - lib/handoff
33
+ - lib/handoff.rb
34
+ - lib/handoff/argument_normalizer.rb
35
+ - lib/handoff/assertion.rb
36
+ - README
37
+ test_files:
38
+ - test/example_test.rb
39
+ - test/handoff_test.rb
40
+ - test/handoff/argument_normalizer_test.rb
41
+ - test/handoff/assertion_test.rb
42
+ rdoc_options: []
43
+
44
+ extra_rdoc_files:
45
+ - README
46
+ executables: []
47
+
48
+ extensions: []
49
+
50
+ requirements: []
51
+
52
+ dependencies:
53
+ - !ruby/object:Gem::Dependency
54
+ name: mocha
55
+ version_requirement:
56
+ version_requirements: !ruby/object:Gem::Version::Requirement
57
+ requirements:
58
+ - - ">"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.0.0
61
+ version: