mocha 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +11 -15
- data/RELEASE +51 -0
- data/Rakefile +27 -3
- data/TODO +5 -10
- data/lib/auto_mocha.rb +1 -0
- data/lib/mocha.rb +6 -1
- data/lib/mocha/auto_verify.rb +41 -0
- data/lib/smart_test_case.rb +5 -0
- data/lib/smart_test_case/multiple_setup_and_teardown.rb +115 -0
- data/lib/stubba.rb +6 -1
- data/lib/stubba/{stubba.rb → central.rb} +1 -1
- data/lib/stubba/setup_and_teardown.rb +19 -0
- data/test/active_record_test_case.rb +36 -0
- data/test/all_tests.rb +30 -51
- data/test/auto_mock_acceptance_test.rb +0 -1
- data/test/mocha/auto_verify_test.rb +49 -0
- data/test/mocha_acceptance_test.rb +8 -22
- data/test/smart_test_case/multiple_setup_and_teardown_test.rb +91 -0
- data/test/stubba/any_instance_method_test.rb +4 -3
- data/test/stubba/{stubba_test.rb → central_test.rb} +9 -8
- data/test/stubba/class_method_test.rb +1 -2
- data/test/stubba/object_test.rb +29 -44
- data/test/stubba/setup_and_teardown_test.rb +76 -0
- data/test/stubba_integration_test.rb +17 -17
- metadata +13 -7
- data/lib/stubba/test_case.rb +0 -65
- data/test/stubba/test_case_test.rb +0 -41
- data/test/stubba_replacer.rb +0 -13
data/README
CHANGED
@@ -2,21 +2,22 @@
|
|
2
2
|
|
3
3
|
Mocha is a library for mocking and stubbing within tests using a syntax like that of JMock[http://www.jmock.org] and SchMock[http://rubyforge.org/projects/schmock].
|
4
4
|
|
5
|
-
Mocha comes in
|
5
|
+
Mocha comes in four parts:
|
6
6
|
|
7
7
|
1. Mocha - traditional mock objects with expectations and verification
|
8
8
|
2. Stubba - allows mocking and stubbing of methods on real (non-mock) classes
|
9
9
|
3. AutoMocha - magically provides mocks in the place of undefined classes
|
10
|
+
4. SmartTestCase - allows addition of multiple setup and teardown methods for a Test::Unit::TestCase
|
10
11
|
|
11
12
|
Stubba and 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
|
|
13
14
|
== Provenance
|
14
15
|
|
15
|
-
Mocha and Stubba have been created by amalgamating a number of techniques developed by me (James[http:blog.floehopper.org]) and my Reevoo[http://www.reevoo.com] colleagues (Ben[http://www.reevoo.com/blogs/bengriffiths/], Chris[http://blog.seagul.co.uk] and Paul[http://po-ru.com]) into a common syntax. They are both in use on real-world Rails[http://www.rubyonrails.org] projects. AutoMocha is more experimental and is at an earlier stage of development.
|
16
|
+
Mocha and Stubba have been created by amalgamating a number of techniques developed by me (James[http:blog.floehopper.org]) and my Reevoo[http://www.reevoo.com] colleagues (Ben[http://www.reevoo.com/blogs/bengriffiths/], Chris[http://blog.seagul.co.uk] and Paul[http://po-ru.com]) into a common syntax. They are both in use on real-world Rails[http://www.rubyonrails.org] projects. AutoMocha is more experimental and is at an earlier stage of development. SmartTestCase has been exrtacted from Mocha and Stubba to remove duplication and allow its use in isolation.
|
16
17
|
|
17
18
|
== Download and Installation
|
18
19
|
|
19
|
-
You can download Mocha from here[http://rubyforge.org/projects/mocha] or install
|
20
|
+
You can download Mocha from here[http://rubyforge.org/projects/mocha] or install it with the following command.
|
20
21
|
|
21
22
|
$ gem install mocha
|
22
23
|
|
@@ -44,20 +45,17 @@ See MochaAcceptanceTest, StubbaAcceptanceTest, AutoMochaAcceptanceTest and unit
|
|
44
45
|
|
45
46
|
end
|
46
47
|
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
require 'rubygems'
|
49
|
+
require 'mocha'
|
50
|
+
require 'test/unit'
|
50
51
|
|
51
52
|
class EnterpriseTest < Test::Unit::TestCase
|
52
53
|
|
53
|
-
include Mocha
|
54
|
-
|
55
54
|
def test_should_boldly_go
|
56
|
-
dilithium =
|
57
|
-
dilithium.expects(:nuke).with(:anti_matter).at_least_once
|
55
|
+
dilithium = mock()
|
56
|
+
dilithium.expects(:nuke).with(:anti_matter).at_least_once # auto-verified at end of test
|
58
57
|
enterprise = Enterprise.new(dilithium)
|
59
58
|
enterprise.go(2)
|
60
|
-
dilithium.verify
|
61
59
|
end
|
62
60
|
|
63
61
|
end
|
@@ -148,12 +146,10 @@ See MochaAcceptanceTest, StubbaAcceptanceTest, AutoMochaAcceptanceTest and unit
|
|
148
146
|
|
149
147
|
class OrderTest < Test::Unit::TestCase
|
150
148
|
|
151
|
-
include Mocha
|
152
|
-
|
153
149
|
# illustrates stubbing of previously undefined class Comment
|
154
150
|
def test_should_return_accepted_comments_for_this_article
|
155
|
-
unaccepted_comment =
|
156
|
-
accepted_comment =
|
151
|
+
unaccepted_comment = stub(:accepted? => false)
|
152
|
+
accepted_comment = stub(:accepted? => true)
|
157
153
|
comments = [unaccepted_comment, accepted_comment]
|
158
154
|
Comment.stubs(:find_all_by_article_id).returns(comments)
|
159
155
|
article = Article.new
|
data/RELEASE
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
= 0.2.0
|
2
|
+
|
3
|
+
* Small change to SetupAndTeardown#teardown_stubs suggested by Luke Redpath (http://www.lukeredpath.co.uk) to allow use of Stubba with RSpec (http://rspec.rubyforge.org).
|
4
|
+
* Reorganized directory structure and extracted addition of setup and teardown methods into SmartTestCase mini-library.
|
5
|
+
* Addition of auto-verify for Mocha (but not Stubba). This means there is more significance in the choice of expects or stubs in that any expects on a mock will automatically get verified.
|
6
|
+
|
7
|
+
So instead of...
|
8
|
+
|
9
|
+
wotsit = Mocha.new
|
10
|
+
wotsit.expects(:thingummy).with(5).returns(10)
|
11
|
+
doobrey = Doobrey.new(wotsit)
|
12
|
+
doobrey.hoojamaflip
|
13
|
+
wotsit.verify
|
14
|
+
|
15
|
+
you need to do...
|
16
|
+
|
17
|
+
wotsit = mock()
|
18
|
+
wotsit.expects(:thingummy).with(5).returns(10)
|
19
|
+
doobrey = Doobrey.new(wotsit)
|
20
|
+
doobrey.hoojamaflip
|
21
|
+
# no need to verify
|
22
|
+
|
23
|
+
There are also shortcuts as follows...
|
24
|
+
|
25
|
+
instead of...
|
26
|
+
|
27
|
+
wotsit = Mocha.new
|
28
|
+
wotsit.expects(:thingummy).returns(10)
|
29
|
+
wotsit.expects(:summat).returns(25)
|
30
|
+
|
31
|
+
you can have...
|
32
|
+
|
33
|
+
wotsit = mock(:thingummy => 5, :summat => 25)
|
34
|
+
|
35
|
+
and instead of...
|
36
|
+
|
37
|
+
wotsit = Mocha.new
|
38
|
+
wotsit.stubs(:thingummy).returns(10)
|
39
|
+
wotsit.stubs(:summat).returns(25)
|
40
|
+
|
41
|
+
you can have...
|
42
|
+
|
43
|
+
wotsit = stub(:thingummy => 5, :summat => 25)
|
44
|
+
|
45
|
+
= 0.1.2
|
46
|
+
|
47
|
+
* Minor tweaks
|
48
|
+
|
49
|
+
= 0.1.1
|
50
|
+
|
51
|
+
* Initial release.
|
data/Rakefile
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake/rdoctask'
|
3
3
|
require 'rake/gempackagetask'
|
4
|
+
require 'rake/contrib/sshpublisher'
|
4
5
|
|
5
6
|
desc "Default task is currently to run all tests"
|
6
7
|
task :default => :test_all
|
@@ -13,9 +14,32 @@ end
|
|
13
14
|
|
14
15
|
desc 'Generate RDoc'
|
15
16
|
Rake::RDocTask.new do |task|
|
17
|
+
task.main = 'README'
|
18
|
+
task.title = 'Mocha'
|
16
19
|
task.rdoc_dir = 'doc'
|
17
|
-
task.options <<
|
18
|
-
task.rdoc_files.include('README', 'lib/**/*.rb')
|
20
|
+
task.options << "--line-numbers" << "--inline-source"
|
21
|
+
task.rdoc_files.include('README', 'RELEASE', 'agiledox.txt', 'lib/**/*.rb')
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Upload RDoc to RubyForge"
|
25
|
+
task :publish_rdoc => [:rdoc] do
|
26
|
+
Rake::SshDirPublisher.new("jamesmead@rubyforge.org", "/var/www/gforge-projects/mocha", "doc").upload
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Generate agiledox-like documentation for tests"
|
30
|
+
file 'agiledox.txt' do
|
31
|
+
File.open('agiledox.txt', 'w') do |output|
|
32
|
+
tests = FileList['test/**/*_test.rb']
|
33
|
+
tests.each do |file|
|
34
|
+
m = %r".*/([^/].*)_test.rb".match(file)
|
35
|
+
output << m[1]+" should:\n"
|
36
|
+
test_definitions = File::readlines(file).select {|line| line =~ /.*def test.*/}
|
37
|
+
test_definitions.sort.each do |definition|
|
38
|
+
m = %r"test_(should_)?(.*)".match(definition)
|
39
|
+
output << " - "+m[2].gsub(/_/," ") << "\n"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
19
43
|
end
|
20
44
|
|
21
45
|
Gem::manage_gems
|
@@ -23,7 +47,7 @@ Gem::manage_gems
|
|
23
47
|
specification = Gem::Specification.new do |s|
|
24
48
|
s.name = "mocha"
|
25
49
|
s.summary = "Mocking and stubbing library"
|
26
|
-
s.version = "0.
|
50
|
+
s.version = "0.2.0"
|
27
51
|
s.author = 'James Mead'
|
28
52
|
s.description = <<-EOF
|
29
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,20 +1,15 @@
|
|
1
|
-
-
|
1
|
+
- make verify method private (makes this unnecessary - fail if attempt to verify stub)
|
2
|
+
- auto-verify for stubs?
|
3
|
+
- allow hash parameter for stubs and expects methods particularly for stubba
|
2
4
|
- write rdoc for most important methods/classes e.g. expectation
|
3
|
-
-
|
4
|
-
- include functionality into test case using module include for more flexibility - instead of re-opening test/unit/test_case
|
5
|
-
- improve implementation of test case setup/teardown
|
6
|
-
- experienced problem when including a module with setup method into a TestCase derived class (something like nil.unstub_all in teardown)
|
5
|
+
- remove mocha/stubba from call stack when assertion error raised
|
7
6
|
- test for setting expectations on class methods (and instance methods?) from within TestCase#setup
|
8
|
-
- test for verifying expectations from within TestCase#teardown
|
9
7
|
- use Object#inspect(:mocha) instead of Object#mocha_inspect?
|
10
8
|
- allow stubbing of private/protected methods?
|
11
9
|
- 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
|
12
|
-
- check if mocking 'new' method is still possible
|
13
10
|
- detect existing or added definition of mocha methods e.g. expects and alias to __expects?
|
14
|
-
-
|
15
|
-
- auto-verify? default to on, allow switch off?
|
11
|
+
- allow switch off of auto-verify?
|
16
12
|
- fail if verify called with no expectations? set expectation - expects(:blah).never to ensure method not called
|
17
|
-
- fail if attempt to verify stub??
|
18
13
|
- maybe use blank_slate as mocha parent class to allow mocking of standard object methods?
|
19
14
|
- more jmock style stuff - e.g. return values on consecutive calls, labels/required order, more sophisticated param matching?
|
20
15
|
- stubs should only return a fixed value - no blocks allowed for return values and no parameter expectations allowed?
|
data/lib/auto_mocha.rb
CHANGED
data/lib/mocha.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'mocha/mock'
|
2
|
+
|
3
|
+
module AutoVerify
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.add_teardown_method(:teardown_mocks)
|
7
|
+
end
|
8
|
+
|
9
|
+
def mocks
|
10
|
+
@mocks ||= []
|
11
|
+
end
|
12
|
+
|
13
|
+
def reset_mocks
|
14
|
+
@mocks = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def mock(expectations = {})
|
18
|
+
mock = Mocha::Mock.new
|
19
|
+
expectations.each do |method, result|
|
20
|
+
mock.expects(method).returns(result)
|
21
|
+
end
|
22
|
+
mocks << mock
|
23
|
+
mock
|
24
|
+
end
|
25
|
+
|
26
|
+
def stub(expectations = {})
|
27
|
+
mock = Mocha::Mock.new
|
28
|
+
expectations.each do |method, result|
|
29
|
+
mock.stubs(method).returns(result)
|
30
|
+
end
|
31
|
+
mocks << mock
|
32
|
+
mock
|
33
|
+
end
|
34
|
+
|
35
|
+
def teardown_mocks
|
36
|
+
mocks.each { |mock| mock.verify }
|
37
|
+
reset_mocks
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module MultipleSetupAndTeardown
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
|
5
|
+
base.class_eval do
|
6
|
+
|
7
|
+
def self.method_added(symbol)
|
8
|
+
# disable until later
|
9
|
+
end
|
10
|
+
|
11
|
+
if method_defined?(:setup) then
|
12
|
+
alias_method :setup_original, :setup
|
13
|
+
define_method(:setup_new) do
|
14
|
+
begin
|
15
|
+
setup_original
|
16
|
+
ensure
|
17
|
+
setup_mocha
|
18
|
+
end
|
19
|
+
end
|
20
|
+
else
|
21
|
+
define_method(:setup_new) do
|
22
|
+
setup_mocha
|
23
|
+
end
|
24
|
+
end
|
25
|
+
alias_method :setup, :setup_new
|
26
|
+
|
27
|
+
if method_defined?(:teardown) then
|
28
|
+
alias_method :teardown_original, :teardown
|
29
|
+
define_method(:teardown_new) do
|
30
|
+
begin
|
31
|
+
teardown_mocha
|
32
|
+
ensure
|
33
|
+
teardown_original
|
34
|
+
end
|
35
|
+
end
|
36
|
+
else
|
37
|
+
define_method(:teardown_new) do
|
38
|
+
teardown_mocha
|
39
|
+
end
|
40
|
+
end
|
41
|
+
alias_method :teardown, :teardown_new
|
42
|
+
|
43
|
+
def self.method_added(method)
|
44
|
+
case method
|
45
|
+
when :setup
|
46
|
+
unless method_defined?(:setup_added)
|
47
|
+
alias_method :setup_added, :setup
|
48
|
+
define_method(:setup) do
|
49
|
+
begin
|
50
|
+
setup_new
|
51
|
+
ensure
|
52
|
+
setup_added
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
when :teardown
|
57
|
+
unless method_defined?(:teardown_added)
|
58
|
+
alias_method :teardown_added, :teardown
|
59
|
+
define_method(:teardown) do
|
60
|
+
begin
|
61
|
+
teardown_added
|
62
|
+
ensure
|
63
|
+
teardown_new
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class << self
|
71
|
+
|
72
|
+
def setup_methods
|
73
|
+
@setup_methods ||= []
|
74
|
+
end
|
75
|
+
|
76
|
+
def teardown_methods
|
77
|
+
@teardown_methods ||= []
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_setup_method(symbol)
|
81
|
+
setup_methods << symbol
|
82
|
+
end
|
83
|
+
|
84
|
+
def add_teardown_method(symbol)
|
85
|
+
teardown_methods << symbol
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def inherited_with_setup_and_teardown_methods(child)
|
91
|
+
inherited_without_setup_and_teardown_methods(child) if respond_to?(:inherited_without_setup_and_teardown_methods, true)
|
92
|
+
child.instance_variable_set('@setup_methods', setup_methods.dup)
|
93
|
+
child.instance_variable_set('@teardown_methods', teardown_methods.dup)
|
94
|
+
end
|
95
|
+
|
96
|
+
if respond_to?(:inherited, true)
|
97
|
+
alias_method :inherited_without_setup_and_teardown_methods, :inherited
|
98
|
+
end
|
99
|
+
alias_method :inherited, :inherited_with_setup_and_teardown_methods
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
def setup_mocha
|
104
|
+
self.class.class_eval { setup_methods }.each { |symbol| send(symbol) }
|
105
|
+
end
|
106
|
+
|
107
|
+
def teardown_mocha
|
108
|
+
self.class.class_eval { teardown_methods }.reverse.each { |symbol| send(symbol) }
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
data/lib/stubba.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'stubba/central'
|
2
|
+
|
3
|
+
module SetupAndTeardown
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.add_setup_method(:setup_stubs)
|
7
|
+
base.add_teardown_method(:teardown_stubs)
|
8
|
+
end
|
9
|
+
|
10
|
+
def setup_stubs
|
11
|
+
$stubba = Stubba::Central.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def teardown_stubs
|
15
|
+
$stubba.unstub_all if $stubba
|
16
|
+
$stubba = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module ActiveRecordTestCase
|
2
|
+
|
3
|
+
def setup_with_fixtures
|
4
|
+
methods_called << :setup_with_fixtures
|
5
|
+
end
|
6
|
+
|
7
|
+
alias_method :setup, :setup_with_fixtures
|
8
|
+
|
9
|
+
def teardown_with_fixtures
|
10
|
+
methods_called << :teardown_with_fixtures
|
11
|
+
end
|
12
|
+
|
13
|
+
alias_method :teardown, :teardown_with_fixtures
|
14
|
+
|
15
|
+
def self.method_added(method)
|
16
|
+
case method.to_s
|
17
|
+
when 'setup'
|
18
|
+
unless method_defined?(:setup_without_fixtures)
|
19
|
+
alias_method :setup_without_fixtures, :setup
|
20
|
+
define_method(:setup) do
|
21
|
+
setup_with_fixtures
|
22
|
+
setup_without_fixtures
|
23
|
+
end
|
24
|
+
end
|
25
|
+
when 'teardown'
|
26
|
+
unless method_defined?(:teardown_without_fixtures)
|
27
|
+
alias_method :teardown_without_fixtures, :teardown
|
28
|
+
define_method(:teardown) do
|
29
|
+
teardown_without_fixtures
|
30
|
+
teardown_with_fixtures
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|