crispy 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +150 -0
- data/Rakefile +2 -0
- data/crispy.gemspec +30 -0
- data/lib/crispy.rb +41 -0
- data/lib/crispy/crispy/received_message.rb +25 -0
- data/lib/crispy/crispy_internal/double.rb +25 -0
- data/lib/crispy/crispy_internal/spy.rb +52 -0
- data/lib/crispy/crispy_internal/spy_mixin.rb +37 -0
- data/lib/crispy/crispy_internal/stubber.rb +31 -0
- data/lib/crispy/crispy_internal/with_stubber.rb +22 -0
- data/lib/crispy/version.rb +3 -0
- data/test/doctest-fixtures/your_cool_class.rb +10 -0
- data/test/test_crispy.rb +145 -0
- metadata +134 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ce5cdae0bd61dc34b874f0d39aff7633c43e7418
|
4
|
+
data.tar.gz: 4865b17724178158276ea6e1134fd614e1cdffb8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e42a8e7746d256b99f4f9fa07ae84f55a154cce1c41a55a41812736249e2b5a49483eeff86d7315de0abd502ad4996ce455605c9283469a400510b81429fa7c3
|
7
|
+
data.tar.gz: a0b29456ff5b7a4b993716c3fbebce7b6c0d71fa1cbc0e8f4ec58cfa5d70448306bb464d8eaf782b3c4d801a6ac2a4fc3595990d62ecfe07fb4a1d0558fc0ad5
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Yamamoto Yuji
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
# Crispy
|
2
|
+
|
3
|
+
Test Spy for Any Object in Ruby.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
7
|
+
- Test spy for any object by using `prepend` (Sorry, it runs by Ruby 2.0 or higher!)
|
8
|
+
- Extremely flexible query for received messages with `received_messages` method.
|
9
|
+
- By using Array and Enumerable's methods, you never have to remember the complex API and tons of the argument matchers in RSpec anymore!
|
10
|
+
- Makes mocks obsolete so you don't have to be worried about where to put the expectations (i.e. *before or after the subject method*).
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
gem 'crispy'
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install crispy
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
<!--
|
29
|
+
# Sample class for doctest.
|
30
|
+
doctest_require: './test/doctest-fixtures/your_cool_class.rb'
|
31
|
+
-->
|
32
|
+
|
33
|
+
### Spy on a Object
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
>> require 'crispy'
|
37
|
+
>> include Crispy # import spy, spy_into and any other functions from Crispy namespace.
|
38
|
+
|
39
|
+
>> object = YourCoolClass.new
|
40
|
+
>> spy = spy_into object
|
41
|
+
|
42
|
+
>> object.your_cool_method 1, 2, 3
|
43
|
+
>> object.your_method_without_argument
|
44
|
+
>> object.your_lovely_method 'great', 'arguments'
|
45
|
+
>> object.your_lovely_method 'great', 'arguments', 'again'
|
46
|
+
>> object.your_finalizer 'resource to release'
|
47
|
+
```
|
48
|
+
|
49
|
+
#### Spy methods with no arguments
|
50
|
+
|
51
|
+
Call query methods through the spy object, instead of YourCoolClass's instance.
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
>> spy(object).received? :your_cool_method
|
55
|
+
=> true
|
56
|
+
>> spy(object).received? :your_method_without_argument
|
57
|
+
=> true
|
58
|
+
>> spy(object).received? :your_lovely_method
|
59
|
+
=> true
|
60
|
+
>> spy(object).received? :your_ugly_method
|
61
|
+
=> false
|
62
|
+
```
|
63
|
+
|
64
|
+
#### Spy methods with arguments
|
65
|
+
|
66
|
+
Each argument is compared by `==` method.
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
>> spy(object).received? :your_cool_method, 1, 2, 3
|
70
|
+
=> true
|
71
|
+
>> spy(object).received? :your_cool_method, 0, 0, 0
|
72
|
+
=> false
|
73
|
+
>> spy(object).received? :your_method_without_argument, :not, :given, :arguments
|
74
|
+
=> false
|
75
|
+
>> spy(object).received? :your_lovely_method, 'great', 'arguments'
|
76
|
+
=> true
|
77
|
+
>> spy(object).received? :your_ugly_method, 'of course', 'I gave no arguments'
|
78
|
+
=> false
|
79
|
+
```
|
80
|
+
|
81
|
+
#### Spy methods with arguments and a block
|
82
|
+
|
83
|
+
*Sorry, I'm still thinking of the specification for that case.*
|
84
|
+
|
85
|
+
#### Count method calls
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
>> spy(object).count_received :your_cool_method
|
89
|
+
=> 1
|
90
|
+
>> spy(object).count_received :your_cool_method, 1, 2, 3
|
91
|
+
=> 1
|
92
|
+
>> spy(object).count_received :your_cool_method, 0, 0, 0
|
93
|
+
=> 0
|
94
|
+
```
|
95
|
+
|
96
|
+
#### Get more detailed log
|
97
|
+
|
98
|
+
You can check arbitrary received methods with the familliar Array's (and of course including Enumerable's!) methods such as `any?`, `all`, `first`, `[]`, `index`.
|
99
|
+
Because `spy(object).received_messages` returns an array of `Crispy::ReceivedMessage` instances.
|
100
|
+
**You don't have to remember the tons of matchers for received arguments any more!!**
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
>>
|
104
|
+
spy(object).received_messages.any? do|m|
|
105
|
+
m.method_name == :your_cool_method && m.arguments.all? {|arg| arg.is_a? Integer }
|
106
|
+
end
|
107
|
+
=> true
|
108
|
+
|
109
|
+
>> last_method_call = spy(object).received_messages.last
|
110
|
+
>>
|
111
|
+
last_method_call.method_name == :your_finalizer &&
|
112
|
+
last_method_call.arguments == ['resource to release']
|
113
|
+
=> true
|
114
|
+
```
|
115
|
+
|
116
|
+
### Stub Methods of a Spy
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
>> spy(object).stub(:your_cool_method, 'Awesome!')
|
120
|
+
>> object.your_cool_method
|
121
|
+
=> "Awesome!"
|
122
|
+
|
123
|
+
>> spy(object).stub(your_lovely_method: 'I love this method!', your_finalizer: 'Finalized!')
|
124
|
+
>> object.your_lovely_method
|
125
|
+
=> "I love this method!"
|
126
|
+
>> object.your_finalizer
|
127
|
+
=> "Finalized!"
|
128
|
+
```
|
129
|
+
|
130
|
+
### Stub Methods of a Double
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
>> your_awesome_double = double('your awesome double', nice!: '+1!', sexy?: true)
|
134
|
+
>> your_awesome_double.nice!
|
135
|
+
=> "+1!"
|
136
|
+
>> your_awesome_double.sexy?
|
137
|
+
=> true
|
138
|
+
|
139
|
+
>> your_awesome_double.stub(:another_method, 'can be stubbed.')
|
140
|
+
>> your_awesome_double.another_method
|
141
|
+
=> "can be stubbed."
|
142
|
+
```
|
143
|
+
|
144
|
+
## Contributing
|
145
|
+
|
146
|
+
1. Fork it ( https://github.com/igrep/crispy/fork )
|
147
|
+
2. Create your feature branch (`git checkout -b your-new-feature`)
|
148
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
149
|
+
4. Push to the branch (`git push origin your-new-feature`)
|
150
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/crispy.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'crispy/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "crispy"
|
7
|
+
spec.version = Crispy::VERSION
|
8
|
+
spec.authors = ["Yamamoto Yuji"]
|
9
|
+
spec.email = ["whosekiteneverfly@gmail.com"]
|
10
|
+
spec.summary = %q{Test spy for any object in Ruby.}
|
11
|
+
spec.description =
|
12
|
+
"Test spy for any object in Ruby.\n" \
|
13
|
+
"It makes mocks obsolete so you don't have to be worried about " \
|
14
|
+
"where to put the expectations (i.e. before or after the subject method)."
|
15
|
+
spec.homepage = "https://github.com/igrep/crispy"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0")
|
19
|
+
spec.executables = []
|
20
|
+
spec.test_files = spec.files.grep(%r{^test/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.4"
|
26
|
+
spec.add_development_dependency "pry"
|
27
|
+
spec.add_development_dependency "rubydoctest"
|
28
|
+
|
29
|
+
spec.required_ruby_version = '>= 2.0'
|
30
|
+
end
|
data/lib/crispy.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require "crispy/version"
|
2
|
+
require "crispy/crispy_internal/spy"
|
3
|
+
require "crispy/crispy_internal/double"
|
4
|
+
|
5
|
+
module Crispy
|
6
|
+
# All methods of this module should be module_function.
|
7
|
+
module_function
|
8
|
+
|
9
|
+
# Returns a Spy object to wrap all methods of the object.
|
10
|
+
def spy_into object, stubs_map = {}
|
11
|
+
::Crispy::CrispyInternal::Spy.new object, stubs_map
|
12
|
+
end
|
13
|
+
|
14
|
+
def double name_or_stubs_map = nil, stubs_map = {}
|
15
|
+
::Crispy::CrispyInternal::Double.new name_or_stubs_map, stubs_map
|
16
|
+
end
|
17
|
+
|
18
|
+
# Make and returns a Crispy::ClassSpy's instance to spy all instances of a class.
|
19
|
+
def spy_on_any_instance_of klass
|
20
|
+
raise NotImplementedError, "Sorry, this feature is under construction :("
|
21
|
+
::Crispy::CrispyInternal::ClassSpy.new klass
|
22
|
+
end
|
23
|
+
|
24
|
+
def spy object
|
25
|
+
object.__CRISPY_SPY__
|
26
|
+
end
|
27
|
+
|
28
|
+
# Begins to log all instances and its received messages of a class.
|
29
|
+
# _NOTE_: replace the constant containing the class
|
30
|
+
def spy_into_class! klass
|
31
|
+
raise NotImplementedError, "Sorry, this feature is under construction :("
|
32
|
+
spy_class = spy_on_any_instance_of klass
|
33
|
+
stub_const! klass.name, spy_class
|
34
|
+
spy_class
|
35
|
+
end
|
36
|
+
|
37
|
+
def stub_const! const_name, value
|
38
|
+
raise NotImplementedError, "Sorry, this feature is under construction :("
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Crispy
|
2
|
+
module Crispy
|
3
|
+
class ReceivedMessage
|
4
|
+
|
5
|
+
attr_reader :method_name, :arguments, :attached_block
|
6
|
+
|
7
|
+
class << self
|
8
|
+
alias [] new
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize method_name, *arguments, &attached_block
|
12
|
+
@method_name = method_name
|
13
|
+
@arguments = arguments
|
14
|
+
@attached_block = attached_block
|
15
|
+
end
|
16
|
+
|
17
|
+
def == other
|
18
|
+
@method_name == other.method_name &&
|
19
|
+
@arguments == other.arguments &&
|
20
|
+
@attached_block == other.attached_block
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'crispy/crispy_internal/with_stubber'
|
2
|
+
|
3
|
+
module Crispy
|
4
|
+
module CrispyInternal
|
5
|
+
class Double
|
6
|
+
include WithStubber
|
7
|
+
|
8
|
+
def initialize name_or_stubs_map = nil, stubs_map = {}
|
9
|
+
if name_or_stubs_map.is_a? ::Hash
|
10
|
+
@name = ''.freeze
|
11
|
+
initialize_stubber(name_or_stubs_map)
|
12
|
+
else
|
13
|
+
@name = name_or_stubs_map
|
14
|
+
initialize_stubber(stubs_map)
|
15
|
+
end
|
16
|
+
singleton_class =
|
17
|
+
class << self
|
18
|
+
self
|
19
|
+
end
|
20
|
+
prepend_stubber singleton_class
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'crispy/crispy/received_message'
|
2
|
+
require 'crispy/crispy_internal/spy_mixin'
|
3
|
+
require 'crispy/crispy_internal/with_stubber'
|
4
|
+
|
5
|
+
module Crispy
|
6
|
+
module CrispyInternal
|
7
|
+
class Spy < ::Module
|
8
|
+
include SpyMixin
|
9
|
+
include WithStubber
|
10
|
+
|
11
|
+
def initialize target, stubs_map = {}
|
12
|
+
super()
|
13
|
+
@received_messages = []
|
14
|
+
singleton_class =
|
15
|
+
class << target
|
16
|
+
self
|
17
|
+
end
|
18
|
+
initialize_stubber stubs_map
|
19
|
+
prepend_stubber singleton_class
|
20
|
+
|
21
|
+
prepend_features singleton_class
|
22
|
+
target.__CRISPY_SPY__ = self
|
23
|
+
end
|
24
|
+
|
25
|
+
def prepend_features klass
|
26
|
+
super
|
27
|
+
klass.public_instance_methods.each do|method_name|
|
28
|
+
self.module_eval { public define_wrapper(method_name) }
|
29
|
+
end
|
30
|
+
klass.protected_instance_methods.each do|method_name|
|
31
|
+
self.module_eval { protected define_wrapper(method_name) }
|
32
|
+
end
|
33
|
+
klass.private_instance_methods.each do|method_name|
|
34
|
+
self.module_eval { private define_wrapper(method_name) }
|
35
|
+
end
|
36
|
+
|
37
|
+
# define accessor after prepending to avoid to spy unexpectedly.
|
38
|
+
module_eval { attr_accessor :__CRISPY_SPY__ }
|
39
|
+
end
|
40
|
+
|
41
|
+
private def define_wrapper method_name
|
42
|
+
define_method method_name do|*arguments, &attached_block|
|
43
|
+
@__CRISPY_SPY__.received_messages <<
|
44
|
+
::Crispy::Crispy::ReceivedMessage.new(method_name, *arguments, &attached_block)
|
45
|
+
super(*arguments, &attached_block)
|
46
|
+
end
|
47
|
+
method_name
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'crispy/crispy/received_message'
|
2
|
+
|
3
|
+
module Crispy
|
4
|
+
module CrispyInternal
|
5
|
+
module SpyMixin
|
6
|
+
|
7
|
+
attr_reader :received_messages
|
8
|
+
|
9
|
+
def received? method_name, *arguments, &attached_block
|
10
|
+
if arguments.empty? and attached_block.nil?
|
11
|
+
@received_messages.map(&:method_name).include? method_name
|
12
|
+
else
|
13
|
+
@received_messages.include? ::Crispy::Crispy::ReceivedMessage.new(method_name, *arguments, &attached_block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def received_once? method_name, *arguments, &attached_block
|
18
|
+
if arguments.empty? and attached_block.nil?
|
19
|
+
@received_messages.map(&:method_name).one? {|self_method_name| self_method_name == method_name }
|
20
|
+
else
|
21
|
+
@received_messages.one? do |self_received_message|
|
22
|
+
self_received_message == ::Crispy::Crispy::ReceivedMessage.new(method_name, *arguments, &attached_block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def count_received method_name, *arguments, &attached_block
|
28
|
+
if arguments.empty? and attached_block.nil?
|
29
|
+
@received_messages.map(&:method_name).count method_name
|
30
|
+
else
|
31
|
+
@received_messages.count ::Crispy::Crispy::ReceivedMessage.new(method_name, *arguments, &attached_block)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Crispy
|
2
|
+
module CrispyInternal
|
3
|
+
class Stubber < Module
|
4
|
+
public :prepend_features
|
5
|
+
|
6
|
+
def initialize stubs_map = {}
|
7
|
+
super()
|
8
|
+
stub stubs_map
|
9
|
+
end
|
10
|
+
|
11
|
+
NOT_SPECIFIED = ::Object.new
|
12
|
+
|
13
|
+
def stub method_name_or_hash, returned_value = NOT_SPECIFIED, &definition
|
14
|
+
case method_name_or_hash
|
15
|
+
when Hash
|
16
|
+
hash = method_name_or_hash
|
17
|
+
hash.each do|method_name, value|
|
18
|
+
stub method_name, value
|
19
|
+
end
|
20
|
+
when ::Symbol, ::String
|
21
|
+
self.module_exec method_name_or_hash do|method_name|
|
22
|
+
# TODO: should not ignore arguments?
|
23
|
+
define_method(method_name) {|*_arguments| returned_value }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'crispy/crispy_internal/stubber'
|
2
|
+
|
3
|
+
module Crispy
|
4
|
+
module CrispyInternal
|
5
|
+
module WithStubber
|
6
|
+
|
7
|
+
private def initialize_stubber stubs_map = {}
|
8
|
+
@__CRISPY_STUBBER__ = Stubber.new(stubs_map)
|
9
|
+
end
|
10
|
+
|
11
|
+
private def prepend_stubber klass
|
12
|
+
@__CRISPY_STUBBER__.prepend_features klass
|
13
|
+
end
|
14
|
+
|
15
|
+
def stub *arguments, &definition
|
16
|
+
@__CRISPY_STUBBER__.stub(*arguments, &definition)
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/test/test_crispy.rb
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
$VERBOSE = true # enable warnings
|
2
|
+
|
3
|
+
require 'crispy'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
|
6
|
+
class TestCrispy < MiniTest::Test
|
7
|
+
include ::Crispy
|
8
|
+
|
9
|
+
# Inherit BasicObject because it has fewer meta-programming methods than Object
|
10
|
+
class ObjectClass < BasicObject
|
11
|
+
def hoge a, b, c
|
12
|
+
private_foo a
|
13
|
+
[a, b, c]
|
14
|
+
end
|
15
|
+
def foo
|
16
|
+
123
|
17
|
+
end
|
18
|
+
def bar
|
19
|
+
[]
|
20
|
+
end
|
21
|
+
def method_to_stub1
|
22
|
+
fail "Not stubbed actually! The test fails."
|
23
|
+
end
|
24
|
+
def method_to_stub2
|
25
|
+
fail "Not stubbed actually! The test fails."
|
26
|
+
end
|
27
|
+
|
28
|
+
private def private_foo a
|
29
|
+
:private_foo
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class TestCrispySpyInto < TestCrispy
|
34
|
+
|
35
|
+
def setup
|
36
|
+
@object = ObjectClass.new
|
37
|
+
|
38
|
+
@returned_spy = spy_into(
|
39
|
+
@object, method_to_stub1: :stubbed1, method_to_stub2: :stubbed2
|
40
|
+
)
|
41
|
+
|
42
|
+
@object.hoge 1, 2, 3
|
43
|
+
@object.foo
|
44
|
+
@object.hoge 3, 4, 5
|
45
|
+
|
46
|
+
@subject = spy(@object)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_spy_logs_messages_sent_to_an_object
|
50
|
+
assert_equal(
|
51
|
+
[
|
52
|
+
Crispy::ReceivedMessage[:hoge, 1, 2, 3],
|
53
|
+
Crispy::ReceivedMessage[:private_foo, 1],
|
54
|
+
Crispy::ReceivedMessage[:foo],
|
55
|
+
Crispy::ReceivedMessage[:hoge, 3, 4, 5],
|
56
|
+
Crispy::ReceivedMessage[:private_foo, 3],
|
57
|
+
],
|
58
|
+
@subject.received_messages
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_spy_has_received_messages_sent_to_an_object
|
63
|
+
assert @subject.received?(:hoge)
|
64
|
+
assert @subject.received?(:foo)
|
65
|
+
assert not(@subject.received?(:bar))
|
66
|
+
assert @subject.received?(:private_foo)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_spy_has_received_messages_with_arguments_sent_to_an_object
|
70
|
+
assert @subject.received?(:hoge, 1, 2, 3)
|
71
|
+
assert @subject.received?(:hoge, 3, 4, 5)
|
72
|
+
assert @subject.received?(:private_foo, 1)
|
73
|
+
assert @subject.received?(:private_foo, 3)
|
74
|
+
assert not(@subject.received?(:hoge, 0, 0, 0))
|
75
|
+
assert not(@subject.received?(:private_foo, 0, 0, 0))
|
76
|
+
assert not(@subject.received?(:foo, 1))
|
77
|
+
assert not(@subject.received?(:bar, nil))
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_spy_has_received_messages_once_sent_to_an_object
|
81
|
+
assert not(@subject.received_once?(:hoge))
|
82
|
+
assert not(@subject.received_once?(:private_foo))
|
83
|
+
assert @subject.received_once?(:hoge, 3, 4, 5)
|
84
|
+
assert @subject.received_once?(:private_foo, 3)
|
85
|
+
assert not(@subject.received_once?(:private_foo, 3, 4))
|
86
|
+
assert @subject.received_once?(:foo)
|
87
|
+
assert not(@subject.received_once?(:bar))
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_spy_counts_received_messages_sent_to_an_object
|
91
|
+
assert_equal(1, @subject.count_received(:hoge, 1, 2, 3))
|
92
|
+
assert_equal(1, @subject.count_received(:hoge, 3, 4, 5))
|
93
|
+
assert_equal(0, @subject.count_received(:hoge, 0, 0, 0))
|
94
|
+
assert_equal(2, @subject.count_received(:hoge))
|
95
|
+
|
96
|
+
assert_equal(1, @subject.count_received(:private_foo, 1))
|
97
|
+
assert_equal(1, @subject.count_received(:private_foo, 3))
|
98
|
+
assert_equal(0, @subject.count_received(:private_foo, 0))
|
99
|
+
assert_equal(2, @subject.count_received(:private_foo))
|
100
|
+
|
101
|
+
assert_equal(1, @subject.count_received(:foo))
|
102
|
+
assert_equal(0, @subject.count_received(:bar))
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_spy_changes_stubbed_method
|
106
|
+
assert_equal(:stubbed1, @object.method_to_stub1)
|
107
|
+
assert_equal(:stubbed2, @object.method_to_stub2)
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_spy_is_also_returned_by_spy_into_method
|
111
|
+
assert_same @subject, @returned_spy
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
class TestCrispyDouble < TestCrispy
|
117
|
+
def setup
|
118
|
+
@expected_hoge = Object.new
|
119
|
+
@expected_foo = Object.new
|
120
|
+
@expected_bar = Object.new
|
121
|
+
@expected_baz = Object.new
|
122
|
+
|
123
|
+
@double = double('some double', hoge: @expected_hoge, foo: @expected_foo)
|
124
|
+
@double.stub(bar: @expected_bar, baz: @expected_baz)
|
125
|
+
|
126
|
+
@actual_hoge1 = @double.hoge :with, :any, :arguments do
|
127
|
+
'and a block'
|
128
|
+
end
|
129
|
+
@actual_hoge2 = @double.hoge
|
130
|
+
@actual_foo = @double.foo
|
131
|
+
@actual_bar = @double.bar
|
132
|
+
@actual_baz = @double.baz
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_double_can_stub_specified_methods
|
136
|
+
assert_same @expected_hoge, @actual_hoge1
|
137
|
+
assert_same @expected_hoge, @actual_hoge2
|
138
|
+
assert_same @expected_foo, @actual_foo
|
139
|
+
assert_same @expected_bar, @actual_bar
|
140
|
+
assert_same @expected_baz, @actual_baz
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: crispy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yamamoto Yuji
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.4'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubydoctest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: |-
|
84
|
+
Test spy for any object in Ruby.
|
85
|
+
It makes mocks obsolete so you don't have to be worried about where to put the expectations (i.e. before or after the subject method).
|
86
|
+
email:
|
87
|
+
- whosekiteneverfly@gmail.com
|
88
|
+
executables: []
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- ".gitignore"
|
93
|
+
- Gemfile
|
94
|
+
- LICENSE.txt
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- crispy.gemspec
|
98
|
+
- lib/crispy.rb
|
99
|
+
- lib/crispy/crispy/received_message.rb
|
100
|
+
- lib/crispy/crispy_internal/double.rb
|
101
|
+
- lib/crispy/crispy_internal/spy.rb
|
102
|
+
- lib/crispy/crispy_internal/spy_mixin.rb
|
103
|
+
- lib/crispy/crispy_internal/stubber.rb
|
104
|
+
- lib/crispy/crispy_internal/with_stubber.rb
|
105
|
+
- lib/crispy/version.rb
|
106
|
+
- test/doctest-fixtures/your_cool_class.rb
|
107
|
+
- test/test_crispy.rb
|
108
|
+
homepage: https://github.com/igrep/crispy
|
109
|
+
licenses:
|
110
|
+
- MIT
|
111
|
+
metadata: {}
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options: []
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '2.0'
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements: []
|
127
|
+
rubyforge_project:
|
128
|
+
rubygems_version: 2.2.2
|
129
|
+
signing_key:
|
130
|
+
specification_version: 4
|
131
|
+
summary: Test spy for any object in Ruby.
|
132
|
+
test_files:
|
133
|
+
- test/doctest-fixtures/your_cool_class.rb
|
134
|
+
- test/test_crispy.rb
|