simple_mock 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +80 -0
- data/Rakefile +10 -0
- data/lib/simple_mock.rb +37 -0
- data/lib/simple_mock/mock_delegator.rb +44 -0
- data/lib/simple_mock/tracer.rb +36 -0
- data/lib/simple_mock/version.rb +3 -0
- data/simple_mock.gemspec +24 -0
- data/test/helper.rb +4 -0
- data/test/unit/mock_delegator_test.rb +62 -0
- data/test/unit/simple_mock_test.rb +11 -0
- data/test/unit/tracer_test.rb +43 -0
- metadata +80 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2012 Tate Johnson <tate@tatey.com>
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# SimpleMock
|
2
|
+
|
3
|
+
[![Build Status](https://secure.travis-ci.org/tatey/simple_mock.png?branch=master)](http://travis-ci.org/tatey/simple_mock)
|
4
|
+
|
5
|
+
A fast, tiny (81 lines) hybrid mocking library. Mix classical mocking with real objects. There's no monkey patching `Object` or copying. Real objects are completely untainted. The interface is 100% compatible with [MiniTest::Mock](https://github.com/seattlerb/minitest) so there is nothing new to learn. SimpleMock's one and only dependancy is Ruby 1.9.2 or greater.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this to your project's Gemfile and run `$ bundle`.
|
10
|
+
|
11
|
+
``` ruby
|
12
|
+
gem 'simple_mock', :group => :test
|
13
|
+
```
|
14
|
+
|
15
|
+
SimpleMock is isolated so there is no need to set require to false.
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
### Classical Mocking
|
20
|
+
|
21
|
+
A new SimpleMock object behaves identically to MiniTest::Mock.
|
22
|
+
|
23
|
+
``` ruby
|
24
|
+
mock_model = SimpleMock.new
|
25
|
+
mock_model.expect :valid?, true
|
26
|
+
|
27
|
+
mock_model.valid? # => true
|
28
|
+
|
29
|
+
mock_model.verify # => true
|
30
|
+
```
|
31
|
+
|
32
|
+
### Hybrid Mocking
|
33
|
+
|
34
|
+
Pass an object to mix expectations with the real object's original behaviour.
|
35
|
+
|
36
|
+
``` ruby
|
37
|
+
class Post < ActiveRecord::Base
|
38
|
+
validates :title, :presence => true
|
39
|
+
end
|
40
|
+
|
41
|
+
real_model = Post.new
|
42
|
+
mock_model = SimpleMock.new real_model
|
43
|
+
mock_model.expect :valid?, true
|
44
|
+
|
45
|
+
mock_model.valid? # => true
|
46
|
+
mock_model.create # => true
|
47
|
+
|
48
|
+
mock_model.verify # => true
|
49
|
+
```
|
50
|
+
|
51
|
+
This is done with delegation, avoiding monkey patching and copying. The real object is completely untainted.
|
52
|
+
|
53
|
+
``` ruby
|
54
|
+
mock_model.valid # => true
|
55
|
+
real_model.valid? # => false
|
56
|
+
|
57
|
+
real_model.object_id == mock_model.__getobj__.object_id # => true
|
58
|
+
```
|
59
|
+
|
60
|
+
More documentation is available at [rubydoc.info](http://rubydoc.info/gems/simple_mock/frames).
|
61
|
+
|
62
|
+
## Caveats
|
63
|
+
|
64
|
+
Like MiniTest::Mock, `#expect` and `#verify` are reserved methods. Expectations should not be defined on real objects which implement these methods. As an alternative, consider creating an anonymous class which inherits from SimpleDelegator.
|
65
|
+
|
66
|
+
``` ruby
|
67
|
+
mock_class = Class.new SimpleDelegator do
|
68
|
+
def verify *args
|
69
|
+
true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
mock_instance = mock_class.new MyRealClass.new
|
73
|
+
mock_instance.verify # => true
|
74
|
+
```
|
75
|
+
|
76
|
+
SimpleMock does something similar to this under the hood.
|
77
|
+
|
78
|
+
## Copyright
|
79
|
+
|
80
|
+
Copyright © 2012 Tate Johnson. SimpleMock is released under the MIT license. See LICENSE for details.
|
data/Rakefile
ADDED
data/lib/simple_mock.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'minitest/mock'
|
4
|
+
|
5
|
+
require 'simple_mock/mock_delegator'
|
6
|
+
require 'simple_mock/tracer'
|
7
|
+
require 'simple_mock/version'
|
8
|
+
|
9
|
+
module SimpleMock
|
10
|
+
|
11
|
+
# Returns a mock instance. For classicial mocking, call +new+ without
|
12
|
+
# an argument.
|
13
|
+
#
|
14
|
+
# mock = SimpleMock.new
|
15
|
+
# mock.expect :meaning_of_life, 42
|
16
|
+
# mock.meaning_of_life # => 42
|
17
|
+
# mock.verify # => true
|
18
|
+
#
|
19
|
+
# For hybrid mocking call +new+ with an +object+ argument. Hybrid mocking
|
20
|
+
# mixes expectations with real objects.
|
21
|
+
#
|
22
|
+
# mock = SimpleMock.new Array.new
|
23
|
+
# mock.expect :meaning_of_life, 42
|
24
|
+
# mock.meaning_of_life # => 42
|
25
|
+
# mock.push(1) # => [1]
|
26
|
+
# mock.verify # => true
|
27
|
+
#
|
28
|
+
# +MiniTest::Mock+ and +SimpleMock::MockDelegator+ have a 100% compatible API
|
29
|
+
# making no difference to the consumer.
|
30
|
+
def self.new object = nil
|
31
|
+
if object.nil?
|
32
|
+
MiniTest::Mock.new
|
33
|
+
else
|
34
|
+
MockDelegator.new object
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module SimpleMock
|
2
|
+
class MockDelegator < SimpleDelegator
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
attr_accessor :__tracer
|
6
|
+
delegate :verify => :__tracer
|
7
|
+
|
8
|
+
def initialize object
|
9
|
+
super
|
10
|
+
self.__tracer = Tracer.new
|
11
|
+
end
|
12
|
+
|
13
|
+
# Expect that method +name+ is called, optionally with +args+, and returns
|
14
|
+
# +retval+.
|
15
|
+
#
|
16
|
+
# mock.expect :meaning_of_life, 42
|
17
|
+
# mock.meaning_of_life # => 42
|
18
|
+
#
|
19
|
+
# mock.expect :do_something_with, true, [some_obj, true]
|
20
|
+
# mock.do_something_with some_obj, true # => true
|
21
|
+
#
|
22
|
+
# +args+ is compared to the expected args using case equality (ie, the
|
23
|
+
# '===' method), allowing for less specific expectations.
|
24
|
+
#
|
25
|
+
# mock.expect :uses_any_string, true, [String]
|
26
|
+
# mock.uses_any_string 'foo' # => true
|
27
|
+
# mock.verify # => true
|
28
|
+
#
|
29
|
+
# mock.expect :uses_one_string, true, ['foo']
|
30
|
+
# mock.uses_one_string 'bar' # => true
|
31
|
+
# mock.verify # => raises MockExpectationError
|
32
|
+
def expect name, retval, args = []
|
33
|
+
method_definition = Module.new do
|
34
|
+
define_method name do |*args, &block|
|
35
|
+
__tracer.assert name, args
|
36
|
+
retval
|
37
|
+
end
|
38
|
+
end
|
39
|
+
extend method_definition
|
40
|
+
__tracer.register name, args
|
41
|
+
self
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module SimpleMock
|
2
|
+
class Tracer
|
3
|
+
attr_accessor :actual_calls, :expected_calls
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
self.actual_calls = {}
|
7
|
+
self.expected_calls = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def assert name, actual_args = []
|
11
|
+
expected_args = expected_calls[name]
|
12
|
+
unless expected_args.size == actual_args.size
|
13
|
+
raise ArgumentError, "mocked method #{name.inspect} expects #{expected_args.size} arguments, got #{actual_args.size}"
|
14
|
+
end
|
15
|
+
unless expected_args.zip(actual_args).all? { |e, a| e === a || e == a }
|
16
|
+
raise MockExpectationError, "mocked method #{name.inspect} called with unexpected arguments #{actual_args.inspect}"
|
17
|
+
end
|
18
|
+
actual_calls[name] = true
|
19
|
+
end
|
20
|
+
|
21
|
+
def register name, args = []
|
22
|
+
expected_calls[name] = args
|
23
|
+
end
|
24
|
+
|
25
|
+
# Verify that all methods were called as expected. Raises
|
26
|
+
# +MockExpectationError+ if not called as expected.
|
27
|
+
def verify
|
28
|
+
differences = expected_calls.keys - actual_calls.keys
|
29
|
+
if differences.any?
|
30
|
+
raise MockExpectationError, "expected #{differences.first.inspect}"
|
31
|
+
else
|
32
|
+
true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/simple_mock.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "simple_mock/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "simple_mock"
|
7
|
+
s.version = SimpleMock::VERSION
|
8
|
+
s.authors = ["Tate Johnson"]
|
9
|
+
s.email = ["tate@tatey.com"]
|
10
|
+
s.homepage = 'https://github.com/tatey/simple_mock'
|
11
|
+
s.summary = %q{A fast, tiny hybrid mocking library.}
|
12
|
+
s.description = %q{A fast, tiny hybrid mocking library. Mix classical mocking with real objects. There's no monkey patching `Object` or copying objects. Real objects are completely untainted.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "simple_mock"
|
15
|
+
|
16
|
+
s.required_ruby_version = '>= 1.9.2'
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
s.add_development_dependency 'rake'
|
24
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class MockDelegatorTest < MiniTest::Unit::TestCase
|
4
|
+
def test_initialize_sets_delegate
|
5
|
+
object = Object.new
|
6
|
+
delegator = MockDelegator.new object
|
7
|
+
assert_equal object, delegator.__getobj__
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_expect_returns_self
|
11
|
+
object = Object.new
|
12
|
+
delegator = MockDelegator.new object
|
13
|
+
assert_equal delegator, delegator.expect(:pop, 1)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_expect_defines_method_returning_value
|
17
|
+
array = Array.new
|
18
|
+
delegator = MockDelegator.new array
|
19
|
+
delegator.expect :pop, 1
|
20
|
+
assert_equal 1, delegator.pop
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_expect_defines_method_with_argument_returning_value
|
24
|
+
array = Array.new
|
25
|
+
delegator = MockDelegator.new array
|
26
|
+
delegator.expect :push, [1, 2], [Fixnum]
|
27
|
+
assert_equal [1, 2], delegator.push(2)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_expect_calls_register_on_tracer
|
31
|
+
tracer = MiniTest::Mock.new
|
32
|
+
tracer.expect :register, true, [:plus_one, []]
|
33
|
+
delegator = MockDelegator.new Object.new
|
34
|
+
delegator.__tracer = tracer
|
35
|
+
delegator.expect :plus_one, 2
|
36
|
+
assert tracer.verify
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_verify_is_forwarded_to_tracer
|
40
|
+
tracer = Class.new { define_method(:verify) { true } }.new
|
41
|
+
delegator = MockDelegator.new Object.new
|
42
|
+
delegator.__tracer = tracer
|
43
|
+
assert_equal true, delegator.verify
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_method_is_forwarded_to_delegate
|
47
|
+
array = Array.new
|
48
|
+
delegator = MockDelegator.new array
|
49
|
+
assert delegator.respond_to?(:push)
|
50
|
+
assert_equal [1], delegator.push(1)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_method_calls_assert_on_tracer
|
54
|
+
tracer = MockDelegator.new Tracer.new
|
55
|
+
tracer.expect :assert, true, [:plus_one, []]
|
56
|
+
delegator = MockDelegator.new Object.new
|
57
|
+
delegator.__tracer = tracer
|
58
|
+
delegator.expect :plus_one, 2
|
59
|
+
delegator.plus_one
|
60
|
+
assert tracer.verify
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class SimpleMockTest < MiniTest::Unit::TestCase
|
4
|
+
def test_new_without_argument_returns_minitest_mock
|
5
|
+
assert_match 'MiniTest::Mock', SimpleMock.new.inspect
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_new_with_argument_returns_mock_delegator
|
9
|
+
assert_instance_of SimpleMock::MockDelegator, SimpleMock.new(Object.new)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TracerTest < MiniTest::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@tracer = Tracer.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_register_stores_expected_method_and_arguments
|
9
|
+
@tracer.register :plus_one, [Fixnum]
|
10
|
+
assert_equal [Fixnum], @tracer.expected_calls[:plus_one]
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_assert_returns_true_when_methods_are_called_as_expected
|
14
|
+
@tracer.register :plus_one, [Fixnum]
|
15
|
+
assert @tracer.assert(:plus_one, [1])
|
16
|
+
assert @tracer.actual_calls[:plus_one]
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_assert_raises_when_methods_are_called_with_wrong_number_of_arguments
|
20
|
+
@tracer.register :plus_one, [Fixnum, Fixnum]
|
21
|
+
e = assert_raises(ArgumentError) { @tracer.assert :plus_one, [1] }
|
22
|
+
assert_equal 'mocked method :plus_one expects 2 arguments, got 1', e.message
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_assert_raises_when_methods_are_called_with_wrong_arguments
|
26
|
+
@tracer.register :plus_one, [Fixnum]
|
27
|
+
e = assert_raises(MockExpectationError) { @tracer.assert :plus_one, [String.new] }
|
28
|
+
assert_equal 'mocked method :plus_one called with unexpected arguments [""]', e.message
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_verify_returns_true_when_methods_are_called_as_expected
|
32
|
+
@tracer.expected_calls = {:plus_one => [Fixnum]}
|
33
|
+
@tracer.actual_calls = {:plus_one => true}
|
34
|
+
assert @tracer.verify
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_verify_raises_when_expected_methods_are_not_called
|
38
|
+
@tracer.expected_calls = {:plus_one => [Fixnum]}
|
39
|
+
@tracer.actual_calls = {:plus_two => true}
|
40
|
+
e = assert_raises(MockExpectationError) { @tracer.verify }
|
41
|
+
assert_equal 'expected :plus_one', e.message
|
42
|
+
end
|
43
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: simple_mock
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tate Johnson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-02-19 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: &70324357134640 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70324357134640
|
25
|
+
description: A fast, tiny hybrid mocking library. Mix classical mocking with real
|
26
|
+
objects. There's no monkey patching `Object` or copying objects. Real objects are
|
27
|
+
completely untainted.
|
28
|
+
email:
|
29
|
+
- tate@tatey.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- .gitignore
|
35
|
+
- .travis.yml
|
36
|
+
- Gemfile
|
37
|
+
- LICENSE
|
38
|
+
- README.md
|
39
|
+
- Rakefile
|
40
|
+
- lib/simple_mock.rb
|
41
|
+
- lib/simple_mock/mock_delegator.rb
|
42
|
+
- lib/simple_mock/tracer.rb
|
43
|
+
- lib/simple_mock/version.rb
|
44
|
+
- simple_mock.gemspec
|
45
|
+
- test/helper.rb
|
46
|
+
- test/unit/mock_delegator_test.rb
|
47
|
+
- test/unit/simple_mock_test.rb
|
48
|
+
- test/unit/tracer_test.rb
|
49
|
+
homepage: https://github.com/tatey/simple_mock
|
50
|
+
licenses: []
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 1.9.2
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
hash: -790596087642070463
|
70
|
+
requirements: []
|
71
|
+
rubyforge_project: simple_mock
|
72
|
+
rubygems_version: 1.8.10
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: A fast, tiny hybrid mocking library.
|
76
|
+
test_files:
|
77
|
+
- test/helper.rb
|
78
|
+
- test/unit/mock_delegator_test.rb
|
79
|
+
- test/unit/simple_mock_test.rb
|
80
|
+
- test/unit/tracer_test.rb
|