facon 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/History.txt ADDED
@@ -0,0 +1,5 @@
1
+ === 0.1 / 2008-02-09
2
+
3
+ * 1 XXX
4
+ * XXX
5
+
data/Manifest.txt ADDED
@@ -0,0 +1,17 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/facon.rb
6
+ lib/facon/baconize.rb
7
+ lib/facon/core_ext/object.rb
8
+ lib/facon/error_generator.rb
9
+ lib/facon/expectation.rb
10
+ lib/facon/mock.rb
11
+ lib/facon/mockable.rb
12
+ lib/facon/proxy.rb
13
+ spec/baconize_spec.rb
14
+ spec/expectation_spec.rb
15
+ spec/mock_spec.rb
16
+ spec/spec_helper.rb
17
+ spec/stub_spec.rb
data/README.txt ADDED
@@ -0,0 +1,87 @@
1
+ = Facon
2
+
3
+ Facon is a mocking library in the spirit of the Bacon spec library. Small, compact, and works with Bacon.
4
+
5
+ == Synopsis
6
+
7
+ To use Facon with Bacon[http://rubyforge.org/projects/test-spec/], simply <code>require 'facon'</code> and you're done.
8
+
9
+ You can now write Bacon specs like this (in RSpec-like style):
10
+
11
+ require 'bacon'
12
+ require 'facon'
13
+
14
+ describe 'PersonController' do
15
+ before do
16
+ @konata = mock('konata', :id => 1, :name => 'Konata Izumi')
17
+ @kagami = mock('kagami', :id => 2, :name => 'Kagami Hiiragi')
18
+ end
19
+
20
+ it "should find all people on GET to 'index'" do
21
+ Person.should.receive(:find).with(:all).and_return([@konata, @kagami])
22
+
23
+ get('/people/index')
24
+ end
25
+
26
+ it "should find the person with id of 1 on Get to 'show/1'" do
27
+ Person.should.receive(:find).with(1).and_return(@konata)
28
+
29
+ get('/people/show/1')
30
+ end
31
+ end
32
+
33
+ For now, more examples can be found in the specs included with the Facon gem. I promise to get better examples into the documentation!
34
+
35
+ See Facon::Baconize for more documentation on using Facon with Bacon[http://rubyforge.org/projects/test-spec/].
36
+
37
+ == Requirements
38
+
39
+ * Ruby 1.8
40
+ * Bacon (optional, required for running specs)
41
+
42
+ == Installation
43
+
44
+ Simply install the gem:
45
+ gem install facon
46
+
47
+ == Links
48
+
49
+ * Facon website - http://facon.rubyforge.org/
50
+ * Facon Rubyforge project - http://rubyforge.org/projects/facon/
51
+ * Bacon - http://rubyforge.org/projects/test-spec/
52
+ * RSpec - http://rspec.info/
53
+
54
+ == Todos
55
+
56
+ * test/unit and RSpec integration.
57
+ * Remove the $facon_mocks global.
58
+
59
+ == Thanks to
60
+
61
+ * RSpec (http://rspec.info/) for creating spec/mocks, from which a lot of the code for Facon is stolen.
62
+ * Christian Neukirchen (http://rubyforge.org/projects/test-spec/) for creating Bacon.
63
+
64
+ == License:
65
+
66
+ (The MIT License)
67
+
68
+ Copyright (c) 2008 Cheah Chu Yeow
69
+
70
+ Permission is hereby granted, free of charge, to any person obtaining
71
+ a copy of this software and associated documentation files (the
72
+ 'Software'), to deal in the Software without restriction, including
73
+ without limitation the rights to use, copy, modify, merge, publish,
74
+ distribute, sublicense, and/or sell copies of the Software, and to
75
+ permit persons to whom the Software is furnished to do so, subject to
76
+ the following conditions:
77
+
78
+ The above copyright notice and this permission notice shall be
79
+ included in all copies or substantial portions of the Software.
80
+
81
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
82
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
83
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
84
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
85
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
86
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
87
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+ $:.unshift(File.dirname(__FILE__) + '/lib')
4
+ require 'facon'
5
+
6
+ Hoe.new('facon', Facon::VERSION) do |p|
7
+ p.rubyforge_name = 'facon'
8
+ p.author = 'Cheah Chu Yeow'
9
+ p.email = 'chuyeow@gmail.com'
10
+ p.summary = 'Tiny mocking library.'
11
+ p.url = 'http://facon.rubyforge.org/'
12
+ p.description = 'A mocking library in the spirit of the Bacon spec library. Small, compact, and works with Bacon.'
13
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
14
+ p.remote_rdoc_dir = 'rdocs'
15
+ # p.clean_globs = ['test/actual'] # Remove this directory on "rake clean"
16
+ end
data/lib/facon.rb ADDED
@@ -0,0 +1,16 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+
3
+ require 'facon/mockable'
4
+ require 'facon/mock'
5
+ require 'facon/error_generator'
6
+ require 'facon/expectation'
7
+ require 'facon/proxy'
8
+ require 'facon/baconize'
9
+
10
+ require 'facon/core_ext/object'
11
+
12
+ # Facon is a mocking library in the spirit of the Bacon spec library. Small,
13
+ # compact, and works with Bacon.
14
+ module Facon
15
+ VERSION = '0.1'
16
+ end
@@ -0,0 +1,95 @@
1
+ module Facon
2
+ # == Bacon integration
3
+ #
4
+ # To use Facon with Bacon, simply <code>require 'facon'</code>. Facon injects
5
+ # itself into Bacon if it can find it, so all you have to do is to make sure
6
+ # you have Bacon and Facon available on the load path.
7
+ #
8
+ # == Example
9
+ #
10
+ # In <code>spec_helper.rb</code>:
11
+ # require 'rubygems'
12
+ # require 'bacon'
13
+ # require 'facon'
14
+ #
15
+ # Simply <code>require</code> your <code>spec_helper.rb</code> in your specs and you are now
16
+ # able to create mocks and expectations:
17
+ #
18
+ # require '/path/to/spec_helper'
19
+ #
20
+ # describe 'My examples' do
21
+ # it "should allow mocks and expectations" do
22
+ # @mock = mock('test mock')
23
+ # @mock.should.receive(:message).and_return(:foo)
24
+ #
25
+ # do_something_with(@mock)
26
+ # end
27
+ # end
28
+ module Baconize
29
+
30
+ # Mixin intended for Bacon::Context so that it runs spec_verify on all mocks
31
+ # after each example.
32
+ module ContextExtensions
33
+ def self.included(base)
34
+ base.class_eval do
35
+ alias_method :it_without_mock_verification, :it
36
+ alias_method :it, :it_with_mock_verification
37
+ end
38
+ end
39
+
40
+ def setup_facon_mocks
41
+ $facon_mocks ||= []
42
+ end
43
+
44
+ def verify_facon_mocks
45
+ $facon_mocks.each { |mock| mock.spec_verify }
46
+ end
47
+
48
+ def it_with_mock_verification(description, &block)
49
+ setup_facon_mocks
50
+ it_without_mock_verification(description, &block)
51
+ verify_facon_mocks
52
+ end
53
+ end
54
+
55
+ # Mixin intended for Bacon's Should class so that we can do
56
+ # mock.should.receive(:message) and mock.should.not.receive(:message).
57
+ module ShouldExtensions
58
+ def self.included(base)
59
+ # Remove Facon::Mockable methods we mixed in to Object, since we don't
60
+ # need those in the Should class.
61
+ base.class_eval do
62
+ instance_methods.each do |method|
63
+ undef_method(method) if Facon::Mockable.public_instance_methods.include?(method)
64
+ end
65
+ end
66
+ end
67
+
68
+ def receive(method, &block)
69
+ if @negated
70
+ @object.mock_proxy.add_negative_expectation(caller(1)[0], method, &block)
71
+ else
72
+ @object.mock_proxy.add_expectation(caller(1)[0], method, &block)
73
+ end
74
+ end
75
+
76
+ private
77
+ def mock_proxy
78
+ @mock_proxy ||= Proxy.new(@object, Mock === @object ? @object.name : @object.class.name)
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+
85
+ begin
86
+ Bacon::Context.class_eval { include Facon::Baconize::ContextExtensions }
87
+ Should.class_eval { include Facon::Baconize::ShouldExtensions }
88
+ rescue NameError
89
+ require 'rubygems'
90
+ require 'bacon'
91
+ Bacon::Context.class_eval { include Facon::Baconize::ContextExtensions }
92
+ Should.class_eval { include Facon::Baconize::ShouldExtensions }
93
+ rescue LoadError
94
+ puts 'Bacon is not available.'
95
+ end
@@ -0,0 +1,3 @@
1
+ class Object #:nodoc:
2
+ include Facon::Mockable
3
+ end
@@ -0,0 +1,42 @@
1
+ module Facon
2
+ # A helper class for generating errors for expectation errors on mocks.
3
+ class ErrorGenerator
4
+ def initialize(target, name)
5
+ @target, @name = target, name
6
+ end
7
+
8
+ def raise_expectation_error(expectation)
9
+ message = "#{target_name} expected :#{expectation.method} with #{format_args(*expectation.argument_expectation)} #{format_count(expectation.expected_received_count)}, but received it #{format_count(expectation.actual_received_count)}"
10
+ raise(Facon::MockExpectationError, message)
11
+ end
12
+
13
+ def raise_unexpected_message_error(method, *args)
14
+ raise(Facon::MockExpectationError, "#{target_name} received unexpected message :#{method} with #{format_args(*args)}")
15
+ end
16
+
17
+ def raise_unexpected_message_args_error(expectation, *args)
18
+ message = "#{target_name} expected :#{expectation.method} with #{format_args(*expectation.argument_expectation)}, but received it with #{format_args(*args)}"
19
+ raise(Facon::MockExpectationError, message)
20
+ end
21
+
22
+ def raise_block_failed_error(method, exception_message)
23
+ message = "#{target_name} received :#{method} but passed block failed with: #{exception_message}"
24
+ raise(Facon::MockExpectationError, message)
25
+ end
26
+
27
+ private
28
+ def target_name
29
+ @name ? "Mock '#{@name}'" : @target.inspect
30
+ end
31
+
32
+ def format_args(*args)
33
+ return '(no args)' if args.empty?
34
+ return '(any args)' if args == [:any]
35
+ "(#{args.map { |a| a.inspect }.join(', ')})"
36
+ end
37
+
38
+ def format_count(count)
39
+ count == 1 ? '1 time' : "#{count} times"
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,130 @@
1
+ require 'forwardable'
2
+
3
+ module Facon
4
+ # An Expectation, also know as a mock method, is an expectation that an object
5
+ # should receive a specific message during the execution of an example.
6
+ class Expectation
7
+ extend ::Forwardable
8
+ def_delegators :@error_generator, :raise_expectation_error, :raise_block_failed_error
9
+
10
+ attr_reader :error_generator, :expectation_ordering, :expected_from, :method, :method_block, :expected_received_count, :actual_received_count, :argument_expectation
11
+
12
+ def initialize(error_generator, expectation_ordering, expected_from, method, method_block, expected_received_count = 1)
13
+ @error_generator = error_generator
14
+ @expectation_ordering = expectation_ordering
15
+ @expected_from = expected_from
16
+ @method = method
17
+ @method_block = method_block
18
+ @expected_received_count = expected_received_count
19
+
20
+ @argument_expectation = :any
21
+ @exception_to_raise = nil
22
+ @symbol_to_throw = nil
23
+ @actual_received_count = 0
24
+ @args_to_yield = []
25
+ end
26
+
27
+ # Sets up the expected method to return the given value.
28
+ def and_return(value)
29
+ raise MockExpectationError, 'Ambiguous return expectation' unless @method_block.nil?
30
+
31
+ @return_block = lambda { value }
32
+ end
33
+
34
+ # Sets up the expected method to yield with the given arguments.
35
+ def and_yield(*args)
36
+ @args_to_yield << args
37
+ self
38
+ end
39
+
40
+ # Sets up the expected method to raise the given <code>exception</code>
41
+ # (default: Exception).
42
+ def and_raise(exception = Exception)
43
+ @exception_to_raise = exception
44
+ end
45
+
46
+ # Sets up the expected method to throw the given <code>symbol</code>.
47
+ def and_throw(sym)
48
+ @symbol_to_throw = sym
49
+ end
50
+
51
+ def with(*args, &block)
52
+ @method_block = block if block
53
+ @argument_expectation = args
54
+ self
55
+ end
56
+
57
+ def invoke(args, block)
58
+ begin
59
+ raise @exception_to_raise unless @exception_to_raise.nil?
60
+ throw @symbol_to_throw unless @symbol_to_throw.nil?
61
+
62
+ return_value = if !@method_block.nil?
63
+ invoke_method_block(args)
64
+ elsif @args_to_yield.size > 0
65
+ @args_to_yield.each { |curr_args| block.call(*curr_args) }
66
+ else
67
+ nil
68
+ end
69
+
70
+ if @return_block
71
+ args << block unless block.nil?
72
+ @return_block.call(*args)
73
+ else
74
+ return_value
75
+ end
76
+ ensure
77
+ @actual_received_count += 1
78
+ end
79
+ end
80
+
81
+ # Returns true if this expectation has been met.
82
+ # TODO at_least and at_most conditions
83
+ def met?
84
+ return true if @expected_received_count == :any ||
85
+ @expected_received_count == @actual_received_count
86
+
87
+ raise_expectation_error(self)
88
+ end
89
+
90
+ # Returns true if the given <code>method</code> and arguments match this
91
+ # Expectation.
92
+ def matches(method, args)
93
+ @method == method && check_arguments(args)
94
+ end
95
+
96
+ # Returns true if the given <code>method</code> matches this Expectation,
97
+ # but the given arguments don't.
98
+ def matches_name_but_not_args(method, args)
99
+ @method == method && !check_arguments(args)
100
+ end
101
+
102
+ def negative_expectation_for?(method)
103
+ false
104
+ end
105
+
106
+ private
107
+ def check_arguments(args)
108
+ case @argument_expectation
109
+ when :any then true
110
+ when args then true
111
+ end
112
+ end
113
+
114
+ def invoke_method_block(args)
115
+ @method_block.call(*args)
116
+ rescue => e
117
+ raise_block_failed_error(@method, e.message)
118
+ end
119
+ end
120
+
121
+ class NegativeExpectation < Expectation
122
+ def initialize(error_generator, expectation_ordering, expected_from, method, method_block, expected_received_count = 0)
123
+ super(error_generator, expectation_ordering, expected_from, method, method_block, expected_received_count)
124
+ end
125
+
126
+ def negative_expectation_for?(method)
127
+ @method == method
128
+ end
129
+ end
130
+ end
data/lib/facon/mock.rb ADDED
@@ -0,0 +1,41 @@
1
+ module Facon
2
+ # Error returned when an expectation on a mock is not satisfied.
3
+ class MockExpectationError < StandardError
4
+ end
5
+
6
+ # A mock object is a 'fake' object on which you can impose simulated behavior.
7
+ # Defining expectations and stubs on mock objects allows you to specify
8
+ # object collaboration without needing to actually instantiate those
9
+ # collaborative objects.
10
+ #
11
+ # == Examples
12
+ #
13
+ # mock = mock('A name')
14
+ # mock = mock('Mock person', :name => 'Konata', :sex => 'female')
15
+ class Mock
16
+ include Facon::Mockable
17
+
18
+ attr_accessor :name
19
+
20
+ def initialize(name, stubs = {})
21
+ @name = name
22
+ stub_out(stubs)
23
+ end
24
+
25
+ def method_missing(method, *args, &block)
26
+ super(method, *args, &block)
27
+ rescue NameError
28
+ # An unexpected method was called on this mock.
29
+ mock_proxy.raise_unexpected_message_error(method, *args)
30
+ end
31
+
32
+ private
33
+
34
+ # Stubs out all the given stubs.
35
+ def stub_out(stubs)
36
+ stubs.each_pair do |method, response|
37
+ stub!(method).and_return(response)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,43 @@
1
+ module Facon
2
+ # A module containing convenient methods for creating mocks, stubs and
3
+ # expectations.
4
+ module Mockable
5
+
6
+ # Shortcut for creating a Facon::Mock instance.
7
+ #
8
+ # == Example
9
+ #
10
+ # mock = mock('test mock', :foo => 'bar')
11
+ # mock.foo # => 'bar'
12
+ def mock(name, stubs = {})
13
+ Mock.new(name, stubs)
14
+ end
15
+
16
+ def stub!(method)
17
+ mock_proxy.add_stub(caller(1)[0], method)
18
+ end
19
+
20
+ def should_receive(method, &block)
21
+ mock_proxy.add_expectation(caller(1)[0], method, &block)
22
+ end
23
+
24
+ def should_not_receive(method, &block)
25
+ mock_proxy.add_negative_expectation(caller(1)[0], method, &block)
26
+ end
27
+
28
+ # Verifies that the expectations set on this mock are all met, otherwise
29
+ # raises a MockExpectationError.
30
+ def spec_verify
31
+ mock_proxy.verify
32
+ end
33
+
34
+ def spec_reset
35
+ mock_proxy.reset
36
+ end
37
+
38
+ # Returns the mock proxy object.
39
+ def mock_proxy
40
+ @mock_proxy ||= Proxy.new(self, Mock === self ? @name : self.class.name)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,99 @@
1
+ require 'forwardable'
2
+
3
+ module Facon
4
+ # A proxy for mock objects. Stubs and expectations are set on this proxy.
5
+ class Proxy
6
+ extend ::Forwardable
7
+ def_delegators :@error_generator, :raise_unexpected_message_error, :raise_unexpected_message_args_error
8
+
9
+ def initialize(target, name)
10
+ @target, @name = target, name
11
+ @expectations = []
12
+ @stubs = []
13
+ @error_generator = ErrorGenerator.new(target, name)
14
+ end
15
+
16
+ def add_stub(expected_from, method)
17
+ $facon_mocks << (@target) unless $facon_mocks.nil?
18
+ define_expected_method(method)
19
+
20
+ # A stub is really an expectation that can be called any number of times.
21
+ @stubs.unshift(Expectation.new(@error_generator, @expectation_ordering, expected_from, method, nil, :any))
22
+ @stubs.first
23
+ end
24
+
25
+ def add_expectation(expected_from, method, &block)
26
+ $facon_mocks << (@target) unless $facon_mocks.nil?
27
+ define_expected_method(method)
28
+
29
+ @expectations << Expectation.new(@error_generator, @expectation_ordering, expected_from, method, (block_given? ? block : nil), 1)
30
+ @expectations.last
31
+ end
32
+
33
+ def add_negative_expectation(expected_from, method, &block)
34
+ $facon_mocks << (@target) unless $facon_mocks.nil?
35
+ define_expected_method(method)
36
+
37
+ @expectations << NegativeExpectation.new(@error_generator, @expectation_ordering, expected_from, method, (block_given? ? block : nil))
38
+ @expectations.last
39
+ end
40
+
41
+ def message_received(method, *args, &block)
42
+ if expectation = find_matching_expectation(method, *args)
43
+ expectation.invoke(args, block)
44
+ elsif stub = find_matching_method_stub(method, *args)
45
+ stub.invoke([], block)
46
+ elsif expectation = find_almost_matching_expectation(method, *args)
47
+ raise_unexpected_message_args_error(expectation, *args) unless has_negative_expectation?(method)
48
+ else
49
+ @target.send(:method_missing, method, *args, &block)
50
+ end
51
+ end
52
+
53
+ def verify
54
+ @expectations.each { |expectation| expectation.met? }
55
+ ensure
56
+ reset
57
+ end
58
+
59
+ def reset
60
+ @expectations.clear
61
+ @stubs.clear
62
+ end
63
+
64
+ private
65
+ # Defines an expected method that simply calls the
66
+ # <code>message_received</code> method.
67
+ def define_expected_method(method)
68
+ metaclass_eval(<<-EOF, __FILE__, __LINE__)
69
+ def #{method}(*args, &block)
70
+ mock_proxy.message_received(:#{method}, *args, &block)
71
+ end
72
+ EOF
73
+ end
74
+
75
+ def metaclass
76
+ (class << @target; self; end)
77
+ end
78
+
79
+ def metaclass_eval(str, filename, lineno)
80
+ metaclass.class_eval(str, filename, lineno)
81
+ end
82
+
83
+ def find_matching_expectation(method, *args)
84
+ @expectations.find { |expectation| expectation.matches(method, args) }
85
+ end
86
+
87
+ def find_almost_matching_expectation(method, *args)
88
+ @expectations.find { |expectation| expectation.matches_name_but_not_args(method, args) }
89
+ end
90
+
91
+ def find_matching_method_stub(method, *args)
92
+ @stubs.find { |stub| stub.matches(method, args) }
93
+ end
94
+
95
+ def has_negative_expectation?(method)
96
+ @expectations.find { |expectation| expectation.negative_expectation_for?(method) }
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,35 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "Facon::Baconize" do
4
+
5
+ before do
6
+ @mock = Facon::Mock.new('test mock')
7
+ end
8
+
9
+ it "should make the #receive instance method available to Should" do
10
+ Should.public_instance_methods.should.include?('receive')
11
+ end
12
+
13
+ it "should allow expectations on mocks with should.receive(:message)" do
14
+ @mock.should.receive(:message).and_return(:foo)
15
+
16
+ @mock.message.should == :foo
17
+ end
18
+
19
+ it "should allow expectations on mocks with should.not.receive(:message)" do
20
+ @mock.should.not.receive(:message)
21
+
22
+ @mock.to_s
23
+ # FIXME: needs a better test on the actual error raised, but the
24
+ # instance_eval in it() makes it hard.
25
+ end
26
+
27
+ it "should allow expectations on arbitrary objects with should.receive(:message)" do
28
+ Object.should.receive(:message).and_return(:foo)
29
+ @object = Object.new
30
+ @object.should.receive(:message).and_return(:bar)
31
+
32
+ Object.message.should == :foo
33
+ @object.message.should == :bar
34
+ end
35
+ end
@@ -0,0 +1,124 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "A mock object" do
4
+ before do
5
+ @mock = Facon::Mock.new('test mock')
6
+ end
7
+
8
+ after do
9
+ @mock.spec_reset
10
+ end
11
+
12
+ def verify_mock
13
+ lambda { @mock.spec_verify }.should.not.raise(Facon::MockExpectationError)
14
+ end
15
+
16
+ it "should pass when not receiving message specified as not to be received" do
17
+ @mock.should_not_receive(:not_expected)
18
+
19
+ verify_mock
20
+ end
21
+
22
+ it "should pass when receiving message specified as not to be received with different args" do
23
+ @mock.should_not_receive(:message).with(:not_this)
24
+ @mock.should_receive(:message).with(:but_this)
25
+ @mock.message(:but_this)
26
+
27
+ verify_mock
28
+ end
29
+
30
+ it "should raise a MockExpectationError when receiving message specified as not to be received" do
31
+ @mock.should_not_receive(:not_expected)
32
+ @mock.not_expected
33
+
34
+ lambda { @mock.spec_verify }.should.raise(Facon::MockExpectationError).message.should == "Mock 'test mock' expected :not_expected with (any args) 0 times, but received it 1 time"
35
+ end
36
+
37
+ it "should raise a MockExpectationError when receiving message specified as not to be received with arguments" do
38
+ @mock.should_not_receive(:not_expected).with(:unexpected_arg)
39
+ @mock.not_expected(:unexpected_arg)
40
+
41
+ lambda { @mock.spec_verify }.should.raise(Facon::MockExpectationError).message.should == "Mock 'test mock' expected :not_expected with (:unexpected_arg) 0 times, but received it 1 time"
42
+ end
43
+
44
+ it "should pass when receiving message specified as not to be received, but with wrong arguments" do
45
+ @mock.should_not_receive(:not_expected).with(:unexpected_arg)
46
+ @mock.not_expected(:wrong_arg)
47
+
48
+ verify_mock
49
+ end
50
+
51
+ it "should raise a MockExpectationError when receiving message specified as to be received is not called" do
52
+ @mock.should_receive(:expected_message)
53
+
54
+ lambda { @mock.spec_verify }.should.raise(Facon::MockExpectationError).message.should == "Mock 'test mock' expected :expected_message with (any args) 1 time, but received it 0 times"
55
+ end
56
+
57
+ it "should raise a MockExpectationError when receiving message specified as to be received, but with wrong arguments" do
58
+ @mock.should_receive(:expected_message).with(:expected_arg)
59
+
60
+ lambda {
61
+ @mock.expected_message(:unexpected_arg)
62
+ }.should.raise(Facon::MockExpectationError).message.should == "Mock 'test mock' expected :expected_message with (:expected_arg), but received it with (:unexpected_arg)"
63
+ end
64
+
65
+ it "should raise a MockExpectationError when receiving an unexpected message" do
66
+ lambda {
67
+ @mock.not_expected
68
+ }.should.raise(Facon::MockExpectationError).message.should == "Mock 'test mock' received unexpected message :not_expected with (no args)"
69
+ end
70
+
71
+ it "should raise a MockExpectationError when receiving an unexpected message with arguments" do
72
+ lambda {
73
+ @mock.not_expected(:foo, :bar)
74
+ }.should.raise(Facon::MockExpectationError).message.should == "Mock 'test mock' received unexpected message :not_expected with (:foo, :bar)"
75
+ end
76
+
77
+ it "should use block for expectation if provided" do
78
+ @mock.should_receive(:expected_message) do |a, b|
79
+ a.should == :first
80
+ b.should == :second
81
+ 'foo'
82
+ end
83
+
84
+ @mock.expected_message(:first, :second).should == 'foo'
85
+
86
+ verify_mock
87
+ end
88
+
89
+ it "should use block with given arguments for expectation if provided" do
90
+ @mock.should_receive(:expected_message).with(:expected_arg) do |arg|
91
+ arg.should == :expected_arg
92
+ 'foo'
93
+ end
94
+
95
+ @mock.expected_message(:expected_arg).should == 'foo'
96
+
97
+ verify_mock
98
+ end
99
+
100
+ it "should raise a MockExpectationError if block for expectation fails" do
101
+ @mock.should_receive(:expected_message) do |arg|
102
+ arg.should == :expected_arg
103
+ end
104
+
105
+ lambda {
106
+ @mock.expected_message(:unexpected_arg)
107
+ }.should.raise(Facon::MockExpectationError).message.should == "Mock 'test mock' received :expected_message but passed block failed with: :unexpected_arg.==(:expected_arg) failed"
108
+ end
109
+
110
+ it "should raise a MockExpectationError if there's a block for expectation and an #and_return expectation is also set" do
111
+ lambda {
112
+ @mock.should_receive(:foo) do
113
+ :this
114
+ end.and_return(:that)
115
+ }.should.raise(Facon::MockExpectationError).message.should == 'Ambiguous return expectation'
116
+ end
117
+ end
118
+
119
+
120
+
121
+
122
+
123
+
124
+
data/spec/mock_spec.rb ADDED
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "Facon::Mock" do
4
+ before do
5
+ @mock = Facon::Mock.new('test mock')
6
+ end
7
+
8
+ it "should stub out a method on a mock" do
9
+ @mock.stub!(:stubbed_method).and_return(:stub_value)
10
+
11
+ @mock.stubbed_method.should == :stub_value
12
+ @mock.stubbed_method.should == :stub_value # called twice to ensure it stays
13
+ end
14
+
15
+ it "should stub out a method on a non-mock" do
16
+ non_mock = Object.new
17
+ non_mock.stub!(:stubbed_method).and_return(:stub_value)
18
+
19
+ non_mock.stubbed_method.should == :stub_value
20
+ non_mock.stubbed_method.should == :stub_value # called twice to ensure it stays
21
+ end
22
+ end
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'bacon'
3
+
4
+ lib_path = File.expand_path("#{File.dirname(__FILE__)}/../lib")
5
+ $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
6
+ require 'facon'
data/spec/stub_spec.rb ADDED
@@ -0,0 +1,127 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "A method stub" do
4
+ before do
5
+ @class = Class.new do
6
+ def self.existing_class_method
7
+ :original_value
8
+ end
9
+
10
+ def existing_instance_method
11
+ :original_value
12
+ end
13
+ end
14
+ @object = @class.new
15
+ end
16
+
17
+ it "should override existing methods" do
18
+ @object.existing_instance_method.should == :original_value
19
+ @object.stub!(:existing_instance_method).and_return(:stubbed_value)
20
+
21
+ @object.existing_instance_method.should == :stubbed_value
22
+ end
23
+
24
+ it "should return the expected value given to #and_return when the stubbed method is received" do
25
+ @object.stub!(:stubbed_method).and_return(:stubbed_value)
26
+
27
+ @object.stubbed_method.should == :stubbed_value
28
+ end
29
+
30
+ it "should ignore when the stubbed method is received" do
31
+ @object.stub!(:stubbed_method)
32
+
33
+ lambda {
34
+ @object.stubbed_method
35
+ }.should.not.raise
36
+ end
37
+
38
+ it "should ignore when the stubbed method is received with arguments" do
39
+ @object.stub!(:stubbed_method)
40
+
41
+ lambda {
42
+ @object.stubbed_method(:some_arg)
43
+ }.should.not.raise
44
+ end
45
+
46
+ it "should yield the argument given to #and_yield" do
47
+ @object.stub!(:yielding_method).and_yield(:yielded)
48
+
49
+ yielded = nil
50
+ @object.yielding_method { |arg| yielded = arg }
51
+
52
+ yielded.should == :yielded
53
+ end
54
+
55
+ it "should yield the multiple arguments given to #and_yield" do
56
+ @object.stub!(:yielding_method).and_yield(:first, :second)
57
+
58
+ first_arg, second_arg = nil, nil
59
+ @object.yielding_method { |arg1, arg2| first_arg, second_arg = arg1, arg2 }
60
+
61
+ first_arg.should == :first
62
+ second_arg.should == :second
63
+ end
64
+
65
+ it "should yield multiple times with multiple calls to #and_yield (i.e. allow chaining of #and_yield calls)" do
66
+ @object.stub!(:yielding_method).and_yield(:one).and_yield(:two)
67
+
68
+ yielded = []
69
+ @object.yielding_method { |arg| yielded << arg }
70
+
71
+ yielded.should == [:one, :two]
72
+ end
73
+
74
+ it "should be able to yield and return different objects (i.e. allow #and_yield and #and_return chaining)" do
75
+ @object.stub!(:yield_and_return).and_yield(:yielded).and_return(:returned)
76
+
77
+ yielded = nil
78
+ @object.yield_and_return { |arg| yielded = arg }.should == :returned
79
+
80
+ yielded.should == :yielded
81
+ end
82
+
83
+ it "should raise the expected exception given to #and_raise" do
84
+ @object.stub!(:failing_method).and_raise(RuntimeError)
85
+
86
+ lambda { @object.failing_method }.should.raise(RuntimeError)
87
+ end
88
+
89
+ it "should throw the expected thrown value given to #and_throw" do
90
+ @object.stub!(:pitch).and_throw(:ball)
91
+
92
+ lambda { @object.pitch }.should.throw(:ball)
93
+ end
94
+
95
+ it "should ignore when the stubbed method is never called" do
96
+ end
97
+ end
98
+
99
+ describe "A method stub with arguments" do
100
+
101
+ before do
102
+ @object = Object.new
103
+ @object.stub!(:stubbed_method).with(:expected_arg).and_return(:stubbed_value)
104
+ end
105
+
106
+ it "should ignore when never called" do
107
+ end
108
+
109
+ it "should ignore when called with expected argument" do
110
+ @object.stubbed_method(:expected_arg)
111
+ end
112
+
113
+ it "should raise a NoMethodError when called with no arguments" do
114
+ lambda { @object.stubbed_method }.should.raise(NoMethodError)
115
+ end
116
+
117
+ it "should raise a NoMethodError when called with some other argument" do
118
+ lambda { @object.stubbed_method(:something_else) }.should.raise(NoMethodError)
119
+ end
120
+
121
+ it "should allow another stub with different arguments" do
122
+ @object.stub!(:stubbed_method).with(:something_else).and_return(:bar)
123
+
124
+ @object.stubbed_method(:expected_arg).should == :stubbed_value
125
+ @object.stubbed_method(:something_else).should == :bar
126
+ end
127
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: facon
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Cheah Chu Yeow
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-02-10 00:00:00 +08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.5.0
23
+ version:
24
+ description: A mocking library in the spirit of the Bacon spec library. Small, compact, and works with Bacon.
25
+ email: chuyeow@gmail.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files:
31
+ - History.txt
32
+ - Manifest.txt
33
+ - README.txt
34
+ files:
35
+ - History.txt
36
+ - Manifest.txt
37
+ - README.txt
38
+ - Rakefile
39
+ - lib/facon.rb
40
+ - lib/facon/baconize.rb
41
+ - lib/facon/core_ext/object.rb
42
+ - lib/facon/error_generator.rb
43
+ - lib/facon/expectation.rb
44
+ - lib/facon/mock.rb
45
+ - lib/facon/mockable.rb
46
+ - lib/facon/proxy.rb
47
+ - spec/baconize_spec.rb
48
+ - spec/expectation_spec.rb
49
+ - spec/mock_spec.rb
50
+ - spec/spec_helper.rb
51
+ - spec/stub_spec.rb
52
+ has_rdoc: true
53
+ homepage: http://facon.rubyforge.org/
54
+ post_install_message:
55
+ rdoc_options:
56
+ - --main
57
+ - README.txt
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ requirements: []
73
+
74
+ rubyforge_project: facon
75
+ rubygems_version: 1.0.1
76
+ signing_key:
77
+ specification_version: 2
78
+ summary: Tiny mocking library.
79
+ test_files: []
80
+