handoff 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +10 -0
- data/lib/handoff/argument_normalizer.rb +20 -0
- data/lib/handoff/assertion.rb +70 -0
- data/lib/handoff.rb +18 -0
- data/test/example_test.rb +41 -0
- data/test/handoff/argument_normalizer_test.rb +23 -0
- data/test/handoff/assertion_test.rb +40 -0
- data/test/handoff_test.rb +17 -0
- metadata +61 -0
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:
|