mocha 0.2.1 → 0.3.0
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 +6 -2
- data/RELEASE +11 -0
- data/Rakefile +1 -1
- data/TODO +1 -3
- data/lib/mocha.rb +1 -0
- data/lib/mocha/auto_verify.rb +18 -13
- data/lib/mocha/expectation.rb +18 -3
- data/lib/mocha/mock.rb +2 -19
- data/lib/mocha/mock_methods.rb +16 -13
- data/lib/shared/backtracefilter.rb +46 -0
- data/lib/smart_test_case/multiple_setup_and_teardown.rb +9 -1
- data/lib/stubba.rb +1 -0
- data/lib/stubba/any_instance_method.rb +9 -5
- data/lib/stubba/central.rb +8 -0
- data/lib/stubba/class_method.rb +15 -11
- data/lib/stubba/instance_method.rb +1 -1
- data/lib/stubba/object.rb +4 -4
- data/lib/stubba/setup_and_teardown.rb +8 -2
- data/test/all_tests.rb +4 -0
- data/test/execution_point.rb +34 -0
- data/test/mocha/auto_verify_test.rb +103 -3
- data/test/mocha/expectation_test.rb +64 -1
- data/test/mocha/mock_methods_test.rb +55 -19
- data/test/mocha/mock_test.rb +11 -38
- data/test/mocha_test_result_integration_test.rb +106 -0
- data/test/smart_test_case/multiple_setup_and_teardown_test.rb +132 -31
- data/test/stubba/any_instance_method_test.rb +14 -2
- data/test/stubba/central_test.rb +62 -2
- data/test/stubba/class_method_test.rb +19 -1
- data/test/stubba/object_test.rb +41 -8
- data/test/stubba/setup_and_teardown_test.rb +60 -2
- data/test/stubba_acceptance_test.rb +0 -5
- data/test/stubba_test_result_integration_test.rb +86 -0
- data/test/test_helper.rb +2 -2
- metadata +6 -2
data/README
CHANGED
@@ -20,6 +20,10 @@ Mocha and Stubba have been created by amalgamating a number of techniques develo
|
|
20
20
|
You can download Mocha from here[http://rubyforge.org/projects/mocha] or install it with the following command.
|
21
21
|
|
22
22
|
$ gem install mocha
|
23
|
+
|
24
|
+
== Ruby on Rails plugin
|
25
|
+
|
26
|
+
$ script/plugin install svn://rubyforge.org/var/svn/mocha/trunk
|
23
27
|
|
24
28
|
== License
|
25
29
|
|
@@ -45,9 +49,9 @@ See MochaAcceptanceTest, StubbaAcceptanceTest, AutoMochaAcceptanceTest and unit
|
|
45
49
|
|
46
50
|
end
|
47
51
|
|
52
|
+
require 'test/unit'
|
48
53
|
require 'rubygems'
|
49
54
|
require 'mocha'
|
50
|
-
require 'test/unit'
|
51
55
|
|
52
56
|
class EnterpriseTest < Test::Unit::TestCase
|
53
57
|
|
@@ -96,9 +100,9 @@ See MochaAcceptanceTest, StubbaAcceptanceTest, AutoMochaAcceptanceTest and unit
|
|
96
100
|
|
97
101
|
end
|
98
102
|
|
103
|
+
require 'test/unit'
|
99
104
|
require 'rubygems'
|
100
105
|
require 'stubba'
|
101
|
-
require 'test/unit'
|
102
106
|
|
103
107
|
class OrderTest < Test::Unit::TestCase
|
104
108
|
|
data/RELEASE
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
= 0.3.0
|
2
|
+
|
3
|
+
* Rails plugin.
|
4
|
+
* Auto-verify for expectations on concrete classes.
|
5
|
+
* Include each expectation verification in the test result assertion count.
|
6
|
+
* Filter out noise from assertion backtraces.
|
7
|
+
* Point assertion backtrace to line where failing expectation was created.
|
8
|
+
* New yields method for expectations.
|
9
|
+
* Create stubs which stub all method calls.
|
10
|
+
* Mocks now respond_to? expected methods.
|
11
|
+
|
1
12
|
= 0.2.1
|
2
13
|
|
3
14
|
* Rename MochaAcceptanceTest::Rover#move method to avoid conflict with Rake (in Ruby 1.8.4 only?)
|
data/Rakefile
CHANGED
@@ -47,7 +47,7 @@ Gem::manage_gems
|
|
47
47
|
specification = Gem::Specification.new do |s|
|
48
48
|
s.name = "mocha"
|
49
49
|
s.summary = "Mocking and stubbing library"
|
50
|
-
s.version = "0.
|
50
|
+
s.version = "0.3.0"
|
51
51
|
s.author = 'James Mead'
|
52
52
|
s.description = <<-EOF
|
53
53
|
Mocking and stubbing library with JMock/SchMock syntax, which allows mocking and stubbing of methods on real (non-mock) classes.
|
data/TODO
CHANGED
@@ -1,15 +1,13 @@
|
|
1
|
+
- think about behaviour when more than one expectation/stubbed method match
|
1
2
|
- make verify method private (makes this unnecessary - fail if attempt to verify stub)
|
2
|
-
- auto-verify for stubs?
|
3
3
|
- allow hash parameter for stubs and expects methods particularly for stubba
|
4
4
|
- write rdoc for most important methods/classes e.g. expectation
|
5
|
-
- remove mocha/stubba from call stack when assertion error raised
|
6
5
|
- test for setting expectations on class methods (and instance methods?) from within TestCase#setup
|
7
6
|
- use Object#inspect(:mocha) instead of Object#mocha_inspect?
|
8
7
|
- allow stubbing of private/protected methods?
|
9
8
|
- should all instances share expectations for any_instance or should each instance have their own - in which case how do we provide access to the instances
|
10
9
|
- detect existing or added definition of mocha methods e.g. expects and alias to __expects?
|
11
10
|
- allow switch off of auto-verify?
|
12
|
-
- fail if verify called with no expectations? set expectation - expects(:blah).never to ensure method not called
|
13
11
|
- maybe use blank_slate as mocha parent class to allow mocking of standard object methods?
|
14
12
|
- more jmock style stuff - e.g. return values on consecutive calls, labels/required order, more sophisticated param matching?
|
15
13
|
- stubs should only return a fixed value - no blocks allowed for return values and no parameter expectations allowed?
|
data/lib/mocha.rb
CHANGED
data/lib/mocha/auto_verify.rb
CHANGED
@@ -15,27 +15,32 @@ module AutoVerify
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def mock(expectations = {})
|
18
|
-
|
19
|
-
expectations.each do |method, result|
|
20
|
-
mock.expects(method).returns(result)
|
21
|
-
end
|
22
|
-
mocks << mock
|
23
|
-
mock
|
18
|
+
build_mock_with_expectations(:expects, expectations)
|
24
19
|
end
|
25
20
|
|
26
21
|
def stub(expectations = {})
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
mock
|
22
|
+
build_mock_with_expectations(:stubs, expectations)
|
23
|
+
end
|
24
|
+
|
25
|
+
def stub_everything(expectations = {})
|
26
|
+
build_mock_with_expectations(:stub_everything, expectations)
|
33
27
|
end
|
34
28
|
|
35
29
|
def teardown_mocks
|
36
|
-
mocks.each { |mock| mock.verify }
|
30
|
+
mocks.each { |mock| mock.verify { add_assertion } }
|
37
31
|
reset_mocks
|
38
32
|
end
|
39
33
|
|
34
|
+
def build_mock_with_expectations(expectation_type = :expects, expectations = {})
|
35
|
+
stub_everything = (expectation_type == :stub_everything)
|
36
|
+
expectation_type = :stubs if expectation_type == :stub_everything
|
37
|
+
mock = Mocha::Mock.new(stub_everything)
|
38
|
+
expectations.each do |method, result|
|
39
|
+
mock.send(expectation_type, method).returns(result)
|
40
|
+
end
|
41
|
+
mocks << mock
|
42
|
+
mock
|
43
|
+
end
|
44
|
+
|
40
45
|
end
|
41
46
|
|
data/lib/mocha/expectation.rb
CHANGED
@@ -15,13 +15,18 @@ module Mocha
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
attr_reader :method_name
|
18
|
+
attr_reader :method_name, :backtrace
|
19
19
|
|
20
|
-
def initialize(method_name)
|
20
|
+
def initialize(method_name, backtrace = nil)
|
21
21
|
@method_name = method_name
|
22
22
|
@count = 1
|
23
23
|
@parameters, @parameter_block = AlwaysEqual.new, nil
|
24
24
|
@invoked, @return_value = 0, nil
|
25
|
+
@backtrace = backtrace || caller
|
26
|
+
end
|
27
|
+
|
28
|
+
def yield?
|
29
|
+
@yield
|
25
30
|
end
|
26
31
|
|
27
32
|
def match?(method_name, *arguments)
|
@@ -57,6 +62,12 @@ module Mocha
|
|
57
62
|
self
|
58
63
|
end
|
59
64
|
|
65
|
+
def yields(*parameters)
|
66
|
+
@yield = true
|
67
|
+
@parameters_to_yield = parameters
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
60
71
|
def returns(value)
|
61
72
|
@return_value = value
|
62
73
|
self
|
@@ -69,12 +80,16 @@ module Mocha
|
|
69
80
|
|
70
81
|
def invoke
|
71
82
|
@invoked += 1
|
83
|
+
yield(*@parameters_to_yield) if yield? and block_given?
|
72
84
|
@return_value.is_a?(Proc) ? @return_value.call : @return_value
|
73
85
|
end
|
74
86
|
|
75
87
|
def verify
|
88
|
+
yield(self) if block_given?
|
76
89
|
unless (@count === @invoked) then
|
77
|
-
|
90
|
+
failure = Test::Unit::AssertionFailedError.new("#{message}: expected calls: #{@count}, actual calls: #{@invoked}")
|
91
|
+
failure.set_backtrace(backtrace)
|
92
|
+
raise failure
|
78
93
|
end
|
79
94
|
end
|
80
95
|
|
data/lib/mocha/mock.rb
CHANGED
@@ -1,30 +1,13 @@
|
|
1
1
|
require 'mocha/mock_methods'
|
2
|
-
require 'test/unit/assertions'
|
3
2
|
|
4
3
|
module Mocha
|
5
4
|
class Mock
|
6
5
|
|
7
6
|
include MockMethods
|
8
7
|
|
9
|
-
|
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
|
8
|
+
def initialize(stub_everything = false)
|
9
|
+
@stub_everything = stub_everything
|
23
10
|
end
|
24
11
|
|
25
|
-
def always_responds
|
26
|
-
Class.new { def respond_to?(symbol); true; end }.new
|
27
|
-
end
|
28
|
-
|
29
12
|
end
|
30
13
|
end
|
data/lib/mocha/mock_methods.rb
CHANGED
@@ -2,25 +2,29 @@ require 'mocha/expectation'
|
|
2
2
|
|
3
3
|
module Mocha
|
4
4
|
module MockMethods
|
5
|
+
|
6
|
+
attr_reader :stub_everything
|
5
7
|
|
6
8
|
def expectations
|
7
9
|
@expectations ||= []
|
8
10
|
end
|
9
11
|
|
10
|
-
def expects(symbol)
|
11
|
-
expectations << Expectation.new(symbol)
|
12
|
+
def expects(symbol, backtrace = nil)
|
13
|
+
expectations << Expectation.new(symbol, backtrace)
|
12
14
|
expectations.last
|
13
15
|
end
|
14
16
|
|
15
|
-
def stubs(symbol)
|
16
|
-
expectations << Stub.new(symbol)
|
17
|
+
def stubs(symbol, backtrace = nil)
|
18
|
+
expectations << Stub.new(symbol, backtrace)
|
17
19
|
expectations.last
|
18
20
|
end
|
19
|
-
|
21
|
+
|
20
22
|
def method_missing(symbol, *arguments, &block)
|
21
23
|
matching_expectation = matching_expectation(symbol, *arguments)
|
22
24
|
if matching_expectation then
|
23
|
-
matching_expectation.invoke
|
25
|
+
matching_expectation.invoke(&block)
|
26
|
+
elsif stub_everything then
|
27
|
+
return
|
24
28
|
else
|
25
29
|
begin
|
26
30
|
super_method_missing(symbol, *arguments, &block)
|
@@ -29,6 +33,10 @@ module Mocha
|
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
36
|
+
|
37
|
+
def respond_to?(symbol)
|
38
|
+
expectations.any? { |expectation| expectation.method_name == symbol }
|
39
|
+
end
|
32
40
|
|
33
41
|
def super_method_missing(symbol, *arguments, &block)
|
34
42
|
raise NoMethodError
|
@@ -42,13 +50,8 @@ module Mocha
|
|
42
50
|
expectations.detect { |expectation| expectation.match?(symbol, *arguments) }
|
43
51
|
end
|
44
52
|
|
45
|
-
def
|
46
|
-
expectations.
|
47
|
-
end
|
48
|
-
|
49
|
-
def verify(*method_names)
|
50
|
-
for_verification = method_names.empty? ? expectations : expectations_matching(method_names)
|
51
|
-
for_verification.each { |expectation| expectation.verify }
|
53
|
+
def verify(&block)
|
54
|
+
expectations.each { |expectation| expectation.verify(&block) }
|
52
55
|
end
|
53
56
|
|
54
57
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Test
|
2
|
+
module Unit
|
3
|
+
module Util
|
4
|
+
module BacktraceFilter
|
5
|
+
|
6
|
+
# quick rip-off of Test::Unit code - there must be a better way of doing this!
|
7
|
+
|
8
|
+
MOCHA_FILE_SEPARATORS = %r{[\\/:]}
|
9
|
+
MOCHA_PREFIX = __FILE__.split(MOCHA_FILE_SEPARATORS)[0..-3]
|
10
|
+
MOCHA_RB_FILE = /\.rb\Z/
|
11
|
+
|
12
|
+
alias_method :__filter_backtrace__, :filter_backtrace
|
13
|
+
|
14
|
+
def filter_backtrace(backtrace, prefix=nil)
|
15
|
+
backtrace = __filter_backtrace__(backtrace, prefix)
|
16
|
+
return ["No backtrace"] unless(backtrace)
|
17
|
+
split_p = if(prefix)
|
18
|
+
prefix.split(MOCHA_FILE_SEPARATORS)
|
19
|
+
else
|
20
|
+
MOCHA_PREFIX
|
21
|
+
end
|
22
|
+
match = proc do |e|
|
23
|
+
split_e = e.split(MOCHA_FILE_SEPARATORS)[0, split_p.size]
|
24
|
+
next false unless(split_e[0..-2] == split_p[0..-2])
|
25
|
+
split_e[-1].sub(MOCHA_RB_FILE, '') == split_p[-1]
|
26
|
+
end
|
27
|
+
return backtrace unless(backtrace.detect(&match))
|
28
|
+
found_prefix = false
|
29
|
+
new_backtrace = backtrace.reverse.reject do |e|
|
30
|
+
if(match[e])
|
31
|
+
found_prefix = true
|
32
|
+
true
|
33
|
+
elsif(found_prefix)
|
34
|
+
false
|
35
|
+
else
|
36
|
+
true
|
37
|
+
end
|
38
|
+
end.reverse
|
39
|
+
new_backtrace = (new_backtrace.empty? ? backtrace : new_backtrace)
|
40
|
+
new_backtrace = new_backtrace.reject(&match)
|
41
|
+
new_backtrace.empty? ? backtrace : new_backtrace
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -105,7 +105,15 @@ module MultipleSetupAndTeardown
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def teardown_mocha
|
108
|
-
|
108
|
+
stored_exception = nil
|
109
|
+
self.class.class_eval { teardown_methods }.reverse.each do |symbol|
|
110
|
+
begin
|
111
|
+
send(symbol)
|
112
|
+
rescue Exception => e
|
113
|
+
stored_exception ||= e
|
114
|
+
end
|
115
|
+
end
|
116
|
+
raise stored_exception if stored_exception
|
109
117
|
end
|
110
118
|
|
111
119
|
end
|
data/lib/stubba.rb
CHANGED
@@ -7,23 +7,27 @@ module Stubba
|
|
7
7
|
def unstub
|
8
8
|
remove_new_method
|
9
9
|
restore_original_method
|
10
|
-
|
10
|
+
stubbee.any_instance.reset_mocha
|
11
|
+
end
|
12
|
+
|
13
|
+
def mock
|
14
|
+
stubbee.any_instance.mocha
|
11
15
|
end
|
12
16
|
|
13
17
|
def hide_original_method
|
14
|
-
|
18
|
+
stubbee.class_eval "alias_method :#{hidden_method}, :#{method}" if stubbee.method_defined?(method)
|
15
19
|
end
|
16
20
|
|
17
21
|
def define_new_method
|
18
|
-
|
22
|
+
stubbee.class_eval "def #{method}(*args, &block); self.class.any_instance.mocha.method_missing(:#{method}, *args, &block); end"
|
19
23
|
end
|
20
24
|
|
21
25
|
def remove_new_method
|
22
|
-
|
26
|
+
stubbee.class_eval "remove_method :#{method}"
|
23
27
|
end
|
24
28
|
|
25
29
|
def restore_original_method
|
26
|
-
|
30
|
+
stubbee.class_eval "alias_method :#{method}, :#{hidden_method}; remove_method :#{hidden_method}" if stubbee.method_defined?(hidden_method)
|
27
31
|
end
|
28
32
|
|
29
33
|
end
|
data/lib/stubba/central.rb
CHANGED
@@ -14,6 +14,14 @@ module Stubba
|
|
14
14
|
stubba_methods.push method
|
15
15
|
end
|
16
16
|
end
|
17
|
+
|
18
|
+
def verify_all(&block)
|
19
|
+
unique_mocks.each { |mock| mock.verify(&block) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def unique_mocks
|
23
|
+
stubba_methods.collect { |method| method.mock }.uniq
|
24
|
+
end
|
17
25
|
|
18
26
|
def unstub_all
|
19
27
|
while stubba_methods.size > 0
|
data/lib/stubba/class_method.rb
CHANGED
@@ -4,10 +4,10 @@ module Stubba
|
|
4
4
|
|
5
5
|
class ClassMethod
|
6
6
|
|
7
|
-
attr_reader :
|
7
|
+
attr_reader :stubbee, :method
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
@
|
9
|
+
def initialize(stubbee, method)
|
10
|
+
@stubbee, @method = stubbee, method
|
11
11
|
end
|
12
12
|
|
13
13
|
def stub
|
@@ -18,23 +18,27 @@ module Stubba
|
|
18
18
|
def unstub
|
19
19
|
remove_new_method
|
20
20
|
restore_original_method
|
21
|
-
|
21
|
+
stubbee.reset_mocha
|
22
|
+
end
|
23
|
+
|
24
|
+
def mock
|
25
|
+
stubbee.mocha
|
22
26
|
end
|
23
27
|
|
24
28
|
def hide_original_method
|
25
|
-
|
29
|
+
stubbee.metaclass.class_eval "alias_method :#{hidden_method}, :#{method}" if stubbee.metaclass.method_defined?(method)
|
26
30
|
end
|
27
31
|
|
28
32
|
def define_new_method
|
29
|
-
|
33
|
+
stubbee.metaclass.class_eval "def #{method}(*args, &block); mocha.method_missing(:#{method}, *args, &block); end"
|
30
34
|
end
|
31
35
|
|
32
36
|
def remove_new_method
|
33
|
-
|
37
|
+
stubbee.metaclass.class_eval "remove_method :#{method}"
|
34
38
|
end
|
35
39
|
|
36
40
|
def restore_original_method
|
37
|
-
|
41
|
+
stubbee.metaclass.class_eval "alias_method :#{method}, :#{hidden_method}; remove_method :#{hidden_method}" if stubbee.metaclass.method_defined?(hidden_method)
|
38
42
|
end
|
39
43
|
|
40
44
|
def hidden_method
|
@@ -42,18 +46,18 @@ module Stubba
|
|
42
46
|
end
|
43
47
|
|
44
48
|
def cannot_replace_method_error
|
45
|
-
Test::Unit::AssertionFailedError.new("Cannot replace #{method} because it is not defined in #{
|
49
|
+
Test::Unit::AssertionFailedError.new("Cannot replace #{method} because it is not defined in #{stubbee}.")
|
46
50
|
end
|
47
51
|
|
48
52
|
def eql?(other)
|
49
53
|
return false unless (other.class == self.class)
|
50
|
-
(
|
54
|
+
(stubbee == other.stubbee) and (method == other.method)
|
51
55
|
end
|
52
56
|
|
53
57
|
alias_method :==, :eql?
|
54
58
|
|
55
59
|
def to_s
|
56
|
-
"#{
|
60
|
+
"#{stubbee}.#{method}"
|
57
61
|
end
|
58
62
|
|
59
63
|
end
|