mocha 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/COPYING +3 -0
  2. data/README +148 -0
  3. data/lib/auto_mocha.rb +1 -0
  4. data/lib/auto_mocha/auto_mock.rb +54 -0
  5. data/lib/auto_mocha/mock_class.rb +38 -0
  6. data/lib/mocha.rb +1 -0
  7. data/lib/mocha/expectation.rb +116 -0
  8. data/lib/mocha/infinite_range.rb +27 -0
  9. data/lib/mocha/inspect.rb +37 -0
  10. data/lib/mocha/metaclass.rb +7 -0
  11. data/lib/mocha/mock.rb +30 -0
  12. data/lib/mocha/mock_methods.rb +55 -0
  13. data/lib/mocha/pretty_parameters.rb +28 -0
  14. data/lib/stubba.rb +2 -0
  15. data/lib/stubba/any_instance_method.rb +31 -0
  16. data/lib/stubba/class_method.rb +61 -0
  17. data/lib/stubba/instance_method.rb +22 -0
  18. data/lib/stubba/object.rb +77 -0
  19. data/lib/stubba/stubba.rb +27 -0
  20. data/lib/stubba/test_case.rb +65 -0
  21. data/test/all_tests.rb +100 -0
  22. data/test/auto_mocha/auto_mock_test.rb +85 -0
  23. data/test/auto_mocha/mock_class_test.rb +179 -0
  24. data/test/auto_mock_acceptance_test.rb +36 -0
  25. data/test/method_definer.rb +18 -0
  26. data/test/mocha/expectation_test.rb +216 -0
  27. data/test/mocha/infinite_range_test.rb +50 -0
  28. data/test/mocha/inspect_test.rb +79 -0
  29. data/test/mocha/mock_methods_test.rb +141 -0
  30. data/test/mocha/mock_test.rb +64 -0
  31. data/test/mocha/pretty_parameters_test.rb +32 -0
  32. data/test/mocha_acceptance_test.rb +112 -0
  33. data/test/stubba/any_instance_method_test.rb +113 -0
  34. data/test/stubba/class_method_test.rb +149 -0
  35. data/test/stubba/instance_method_test.rb +97 -0
  36. data/test/stubba/object_test.rb +147 -0
  37. data/test/stubba/stubba_test.rb +62 -0
  38. data/test/stubba/test_case_test.rb +41 -0
  39. data/test/stubba_acceptance_test.rb +107 -0
  40. data/test/stubba_integration_test.rb +59 -0
  41. data/test/stubba_replacer.rb +13 -0
  42. data/test/test_helper.rb +4 -0
  43. metadata +91 -0
data/COPYING ADDED
@@ -0,0 +1,3 @@
1
+ Copyright Revieworld Ltd. 2006
2
+
3
+ You may use, copy and redistribute this library under the same terms as Ruby itself (see http://www.ruby-lang.org/en/LICENSE.txt).
data/README ADDED
@@ -0,0 +1,148 @@
1
+ = Mocha
2
+
3
+ Mocha is a library for mocking and stubbing with unit tests using a syntax like that of JMock[http://www.jmock.org] and SchMock[http://rubyforge.org/projects/schmock].
4
+
5
+ Mocha comes in three parts:
6
+
7
+ 1. Mocha - traditional mock objects with expectations and verification
8
+ 2. Stubba - allows mocking and stubbing of methods on real (non-mock) classes
9
+ 3. AutoMocha - magically provides mocks in the place of undefined classes
10
+
11
+ Stubba & AutoMocha are the main difference between this mocking library and others like FlexMock[http://onestepback.org/software/flexmock] and RSpec[http://rspec.rubyforge.org].
12
+
13
+ == Provenance
14
+
15
+ Mocha & Stubba have been created by amalgamating a number of techniques developed by my Reevoo[http://www.reevoo.com] colleagues (Ben[http://www.reevoo.com/blogs/bengriffiths/], Chris[http://blog.seagul.co.uk] & Paul[http://po-ru.com]) and I[http:blog.floehopper.org] under a common syntax. They are both in use on real-world projects using {Ruby On Rails}[http://www.rubyonrails.org]. AutoMocha is more experimental and is at an earlier stage of development.
16
+
17
+ == Download & Installation
18
+
19
+ You can download Mocha from here[http://rubyforge.org/projects/mocha] or install Mocha with the following command.
20
+
21
+ $ gem install flexmock
22
+
23
+ == License
24
+
25
+ Copyright Revieworld Ltd. 2006
26
+
27
+ You may use, copy and redistribute this library under the same terms as Ruby itself (see http://www.ruby-lang.org/en/LICENSE.txt).
28
+
29
+ == Simple Mocha Example
30
+
31
+ class Enterprise
32
+
33
+ def initialize(dilithium)
34
+ @dilithium = dilithium
35
+ end
36
+
37
+ def go(warp_factor)
38
+ warp_factor.times { @dilithium.nuke(:anti_matter) }
39
+ end
40
+
41
+ end
42
+
43
+ require 'mocha'
44
+
45
+ class EnterpriseTest < Test::Unit::TestCase
46
+
47
+ include Mocha
48
+
49
+ def test_should_boldly_go
50
+ dilithium = Mock.new
51
+ dilithium.expects(:nuke).with(:anti_matter).at_least_once
52
+ enterprise = Enterprise.new(dilithium)
53
+ enterprise.go(2)
54
+ dilithium.verify
55
+ end
56
+
57
+ end
58
+
59
+ == Simple Stubba Example
60
+
61
+ class Order
62
+
63
+ def total_cost
64
+ line_items.inject(0) { |total, line_item| total + line_item.price } + shipping_cost
65
+ end
66
+
67
+ def total_weight
68
+ line_items.inject(0) { |total, line_item| total + line_item.weight }
69
+ end
70
+
71
+ def shipping_cost
72
+ total_weight * 5 + 10
73
+ end
74
+
75
+ class << self
76
+
77
+ def find_all
78
+ Database.connection.select_all('select * from orders')
79
+ end
80
+
81
+ def number_shipped_since(date)
82
+ find_all.select { |order| order.shipped_on > date }.size
83
+ end
84
+
85
+ def unshipped_value
86
+ find_all.inject(0) { |order| order.shipped_on ? 0 : order.total_cost }
87
+ end
88
+
89
+ end
90
+ end
91
+
92
+ require 'stubba'
93
+
94
+ class OrderTest < Test::Unit::TestCase
95
+
96
+ # illustrates stubbing instance method
97
+ def test_should_calculate_shipping_cost_based_on_total_weight
98
+ order = Order.new
99
+ order.stubs(:total_weight).returns(10)
100
+ assert_equal 60, order.shipping_cost
101
+ end
102
+
103
+ # illustrates stubbing class method
104
+ def test_should_count_number_of_orders_shipped_after_specified_date
105
+ order_1 = Order.new(:shipped_on => 1.week.ago)
106
+ order_2 = Order.new(:shipped_on => 3.weeks.ago)
107
+ Order.stubs(:find_all).returns([order_1, order_2])
108
+ assert_equal 1, Order.number_shipped_since(2.weeks.ago)
109
+ end
110
+
111
+ # illustrates stubbing instance method for all instances of a class
112
+ def test_should_calculate_value_of_unshipped_orders
113
+ order_1 = Order.create
114
+ order_2 = Order.create
115
+ Order.any_instance.stubs(:shipped_on).returns(Time.now)
116
+ Order.any_instance.stubs(:total_cost).returns(10)
117
+ assert_equal 20, Order.unshipped_value
118
+ end
119
+
120
+ end
121
+
122
+ == Simple AutoMocha Example
123
+
124
+ class Article
125
+
126
+ def accepted_comments
127
+ Comment.find_all_by_article_id(self.id).select { |comment| comment.accepted? }
128
+ end
129
+
130
+ end
131
+
132
+ require 'auto_mocha'
133
+
134
+ class OrderTest < Test::Unit::TestCase
135
+
136
+ include Mocha
137
+
138
+ # illustrates stubbing of previously undefined class Comment
139
+ def test_should_return_accepted_comments_for_this_article
140
+ unaccepted_comment = Mock.new(:accepted? => false)
141
+ accepted_comment = Mock.new(:accepted? => true)
142
+ comments = [unaccepted_comment, accepted_comment]
143
+ Comment.stubs(:find_all_by_article_id).returns(comments)
144
+ article = Article.new
145
+ assert_equal [accepted_comment], article.accepted_comments
146
+ end
147
+
148
+ end
@@ -0,0 +1 @@
1
+ require 'auto_mocha/auto_mock'
@@ -0,0 +1,54 @@
1
+ require 'auto_mocha/mock_class'
2
+
3
+ class Module
4
+
5
+ def mochas
6
+ @@mochas ||= {}
7
+ end
8
+
9
+ def reset_mochas
10
+ @@mochas = nil
11
+ end
12
+
13
+ def const_missing(symbol)
14
+ mochas[symbol] ||= Mocha::MockClass.dup
15
+ end
16
+
17
+ def verify_all
18
+ mochas.each_value { |mocha| mocha.verify_all }
19
+ end
20
+
21
+ end
22
+
23
+ Mocha::MockClass.class_eval do
24
+
25
+ class << self
26
+
27
+ def mochas
28
+ @mochas ||= {}
29
+ end
30
+
31
+ def const_missing(symbol)
32
+ mochas[symbol] ||= Mocha::MockClass.dup
33
+ end
34
+
35
+ def verify_all
36
+ mochas.each_value { |mocha| mocha.verify }
37
+ verify
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+
44
+ class Test::Unit::TestCase
45
+
46
+ def reset_mochas
47
+ Object.reset_mochas
48
+ end
49
+
50
+ def verify_all
51
+ Object.verify_all
52
+ end
53
+
54
+ end
@@ -0,0 +1,38 @@
1
+ require 'mocha/mock_methods'
2
+
3
+ module Mocha
4
+
5
+ class MockClass
6
+
7
+ include MockMethods
8
+
9
+ class << self
10
+
11
+ include MockMethods
12
+
13
+ def super_method_missing(symbol, *arguments, &block)
14
+ superclass.method_missing(symbol, *arguments, &block)
15
+ end
16
+
17
+ alias_method :__new__, :new
18
+
19
+ def new(*arguments, &block)
20
+ method_missing(:new, *arguments, &block)
21
+ end
22
+
23
+ def inherited(subclass)
24
+ subclass.class_eval do
25
+
26
+ def self.new(*arguments, &block)
27
+ __new__(*arguments, &block)
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1 @@
1
+ require 'mocha/mock'
@@ -0,0 +1,116 @@
1
+ require 'mocha/infinite_range'
2
+ require 'mocha/pretty_parameters'
3
+
4
+ module Mocha
5
+ class Expectation
6
+
7
+ class InvalidExpectation < Exception; end
8
+
9
+ class AlwaysEqual
10
+ def ==(other)
11
+ true
12
+ end
13
+ def to_s
14
+ "** any **"
15
+ end
16
+ end
17
+
18
+ attr_reader :method_name
19
+
20
+ def initialize(method_name)
21
+ @method_name = method_name
22
+ @count = 1
23
+ @parameters, @parameter_block = AlwaysEqual.new, nil
24
+ @invoked, @return_value = 0, nil
25
+ end
26
+
27
+ def match?(method_name, *arguments)
28
+ if @parameter_block then
29
+ @parameter_block.call(*arguments)
30
+ else
31
+ (@method_name == method_name) and (@parameters == arguments)
32
+ end
33
+ end
34
+
35
+ def times(range)
36
+ @count = range
37
+ self
38
+ end
39
+
40
+ def never
41
+ times(0)
42
+ end
43
+
44
+ def at_least(minimum)
45
+ times(Range.at_least(minimum))
46
+ self
47
+ end
48
+
49
+ def at_least_once()
50
+ at_least(1)
51
+ self
52
+ end
53
+
54
+ def with(*arguments, &parameter_block)
55
+ @parameters, @parameter_block = arguments, parameter_block
56
+ class << @parameters; def to_s; join(', '); end; end
57
+ self
58
+ end
59
+
60
+ def returns(value)
61
+ @return_value = value
62
+ self
63
+ end
64
+
65
+ def raises(exception = RuntimeError, message = nil)
66
+ @return_value = lambda{ raise exception, message }
67
+ self
68
+ end
69
+
70
+ def invoke
71
+ @invoked += 1
72
+ @return_value.is_a?(Proc) ? @return_value.call : @return_value
73
+ end
74
+
75
+ def verify
76
+ unless (@count === @invoked) then
77
+ raise Test::Unit::AssertionFailedError, "#{message}: expected calls: #{@count}, actual calls: #{@invoked}"
78
+ end
79
+ end
80
+
81
+ def message
82
+ params = @parameters.is_a?(Array) ? @parameters : [@parameters.to_s]
83
+ params = PrettyParameters.new(params)
84
+ ":#{@method_name}(#{params.pretty})"
85
+ end
86
+
87
+ end
88
+
89
+ class Stub < Expectation
90
+
91
+ def verify
92
+ true
93
+ end
94
+
95
+ end
96
+
97
+ class MissingExpectation < Expectation
98
+
99
+ def initialize(method_name, expectations = [])
100
+ super(method_name)
101
+ @expectations = expectations
102
+ @invoked = true
103
+ end
104
+
105
+ def verify
106
+ msg = "Unexpected message #{message}"
107
+ msg << "\nSimilar expectations #{similar_expectations.collect { |expectation| expectation.message }.join("\n") }" unless similar_expectations.empty?
108
+ raise Test::Unit::AssertionFailedError, msg if @invoked
109
+ end
110
+
111
+ def similar_expectations
112
+ @expectations.select { |expectation| expectation.method_name == self.method_name }
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,27 @@
1
+ class Range
2
+
3
+ def self.at_least(minimum_value)
4
+ Range.new(minimum_value, infinite)
5
+ end
6
+
7
+ def self.at_most(maximum_value)
8
+ Range.new(-infinite, maximum_value, false)
9
+ end
10
+
11
+ def self.infinite
12
+ 1/0.0
13
+ end
14
+
15
+ alias_method :__to_s__, :to_s
16
+
17
+ def to_s
18
+ if first.to_f.infinite? then
19
+ return "at most #{last}"
20
+ elsif last.to_f.infinite? then
21
+ return "at least #{first}"
22
+ else
23
+ __to_s__
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,37 @@
1
+ require 'date'
2
+
3
+ class Object
4
+ def mocha_inspect
5
+ inspect =~ /#</ ? "#<#{self.class}: #{self.object_id}>" : inspect
6
+ end
7
+ end
8
+
9
+ class String
10
+ def mocha_inspect
11
+ inspect.gsub(/\"/, "'")
12
+ end
13
+ end
14
+
15
+ class Array
16
+ def mocha_inspect
17
+ "[#{collect { |member| member.mocha_inspect }.join(', ')}]"
18
+ end
19
+ end
20
+
21
+ class Hash
22
+ def mocha_inspect
23
+ "{#{collect { |key, value| "#{key.mocha_inspect} => #{value.mocha_inspect}" }.join(', ')}}"
24
+ end
25
+ end
26
+
27
+ class Time
28
+ def mocha_inspect
29
+ "#{inspect} (#{to_f} secs)"
30
+ end
31
+ end
32
+
33
+ class Date
34
+ def mocha_inspect
35
+ to_s
36
+ end
37
+ end
@@ -0,0 +1,7 @@
1
+ class Object
2
+
3
+ def metaclass
4
+ class << self; self; end
5
+ end
6
+
7
+ end
@@ -0,0 +1,30 @@
1
+ require 'mocha/mock_methods'
2
+ require 'test/unit/assertions'
3
+
4
+ module Mocha
5
+ class Mock
6
+
7
+ include MockMethods
8
+
9
+ attr_reader :mocked
10
+
11
+ def initialize(*arguments)
12
+ @mocked = arguments.shift unless arguments.first.is_a?(Hash)
13
+ @mocked ||= always_responds
14
+ expectations = arguments.shift || {}
15
+ expectations.each do |method_name, result|
16
+ expects(method_name).returns(result)
17
+ end
18
+ end
19
+
20
+ def expects(symbol)
21
+ raise Test::Unit::AssertionFailedError, "Cannot replace #{symbol} as #{@mocked} does not respond to it." unless @mocked.respond_to?(symbol)
22
+ super
23
+ end
24
+
25
+ def always_responds
26
+ Class.new { def respond_to?(symbol); true; end }.new
27
+ end
28
+
29
+ end
30
+ end