handoff 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|