rspec-spy 0.0.1 → 0.0.2
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.md +72 -3
- data/lib/rspec-spy.rb +8 -85
- data/lib/rspec/core/spy_proxy.rb +43 -0
- data/lib/rspec/spy.rb +16 -0
- data/lib/rspec/spy/example_group_methods.rb +20 -0
- data/lib/rspec/spy/mock_methods.rb +27 -0
- data/lib/{rspec-spy → rspec/spy}/version.rb +1 -1
- data/rspec-spy.gemspec +1 -1
- data/spec/rspec_spy_spec.rb +48 -4
- metadata +12 -8
data/README.md
CHANGED
@@ -1,6 +1,28 @@
|
|
1
|
-
#
|
1
|
+
# RSpec::Spy
|
2
2
|
|
3
|
-
|
3
|
+
This gem allows you to write mock expectations in an AAA (Arrange-Act-Assert) fashion
|
4
|
+
with RSpec::Mocks. It does this by allowing you to declare examples within a spy block,
|
5
|
+
which is effectively executed before everything else. Here's a simple example:
|
6
|
+
|
7
|
+
``` ruby
|
8
|
+
describe "Example" do
|
9
|
+
let(:collaborator) { stub.as_null_object }
|
10
|
+
|
11
|
+
before do
|
12
|
+
collaborator.message
|
13
|
+
end
|
14
|
+
|
15
|
+
spy do
|
16
|
+
it "should receive a message" do
|
17
|
+
collaborator.should_receive :message
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should not receive other_message" do
|
21
|
+
collaborator.should_not_receive :other_message
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
```
|
4
26
|
|
5
27
|
## Installation
|
6
28
|
|
@@ -18,7 +40,54 @@ Or install it yourself as:
|
|
18
40
|
|
19
41
|
## Usage
|
20
42
|
|
21
|
-
|
43
|
+
Add to your spec_helper.rb:
|
44
|
+
|
45
|
+
``` ruby
|
46
|
+
require 'rspec-spy'
|
47
|
+
```
|
48
|
+
|
49
|
+
If you want to be warned when using should_receive outside of spy blocks (recommended)
|
50
|
+
add this to your spec_helper.rb:
|
51
|
+
|
52
|
+
``` ruby
|
53
|
+
# Require should_receive and should_not_receive to be inside spy blocks
|
54
|
+
# Use should_receive! and should_not_receive! outside spy blocks
|
55
|
+
RSpec::Spy.strict_mode = true
|
56
|
+
```
|
57
|
+
|
58
|
+
Now just put your spy expectations within spy blocks in your specs. You should be able to
|
59
|
+
use all of the functionality from rspec-mocks that you're used to, including spying on
|
60
|
+
class methods.
|
61
|
+
|
62
|
+
``` ruby
|
63
|
+
spy do
|
64
|
+
it "should receive message" do
|
65
|
+
collaborator.should_receive :message
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Shorthand:
|
70
|
+
spy.it "should receive message" do
|
71
|
+
collaborator.should_receive :message
|
72
|
+
end
|
73
|
+
```
|
74
|
+
|
75
|
+
## Warnings
|
76
|
+
|
77
|
+
* This is a hack, you'll want to make sure everyone on your team is aware of the behavior
|
78
|
+
and these warnings. You may not actually even want to use this.
|
79
|
+
* You should probably avoid instance vars, it gets confusing because you cannot set them
|
80
|
+
in before blocks and use them in spy blocks. Remember, spy blocks actually happen before
|
81
|
+
before blocks.
|
82
|
+
* If your tests depend on the method you are spying on returning something then you'll
|
83
|
+
need to use `and_return` in your spy block and if you have normal examples you'll also
|
84
|
+
need to stub it. Yes, this is annoying, but that's how rspec-mocks works.
|
85
|
+
|
86
|
+
## Alternatives
|
87
|
+
|
88
|
+
* [matahari](https://github.com/mortice/matahari)
|
89
|
+
* [bourne](https://github.com/thoughtbot/bourne)
|
90
|
+
* [rspec-spies](https://github.com/technicalpickles/rspec-spies)
|
22
91
|
|
23
92
|
## Contributing
|
24
93
|
|
data/lib/rspec-spy.rb
CHANGED
@@ -1,88 +1,11 @@
|
|
1
|
-
require 'rspec
|
2
|
-
|
3
|
-
require 'rspec/
|
4
|
-
require 'rspec/
|
5
|
-
|
6
|
-
RSpec
|
7
|
-
|
8
|
-
|
9
|
-
end
|
10
|
-
|
11
|
-
alias_method :should_receive!, :should_receive
|
12
|
-
alias_method :should_receive, :should_receive_with_spy_check
|
13
|
-
|
14
|
-
def should_not_receive_with_spy_check(*args, &block)
|
15
|
-
should_not_receive!(*args, &block)
|
1
|
+
require 'rspec/spy/version'
|
2
|
+
require 'rspec/spy'
|
3
|
+
require 'rspec/spy/mock_methods'
|
4
|
+
require 'rspec/spy/example_group_methods'
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.before(:each) do |example|
|
8
|
+
example.spy_setup if example.respond_to? :spy_setup
|
16
9
|
end
|
17
|
-
|
18
|
-
alias_method :should_not_receive!, :should_not_receive
|
19
|
-
alias_method :should_not_receive, :should_not_receive_with_spy_check
|
20
10
|
end
|
21
11
|
|
22
|
-
require 'rspec/core/hooks'
|
23
|
-
module RSpec
|
24
|
-
module Spy
|
25
|
-
def self.included(mod)
|
26
|
-
mod.extend ExampleGroupMethods
|
27
|
-
end
|
28
|
-
|
29
|
-
class SpyProxy
|
30
|
-
def initialize(example_group)
|
31
|
-
@example_group = example_group
|
32
|
-
end
|
33
|
-
|
34
|
-
def example_method(method, description, *args, &block)
|
35
|
-
@example_group.context do
|
36
|
-
let(:__spy__, &block)
|
37
|
-
|
38
|
-
send(method, description, *args) do
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
[
|
44
|
-
:example,
|
45
|
-
:it,
|
46
|
-
:specify,
|
47
|
-
:focused,
|
48
|
-
:focus,
|
49
|
-
:pending,
|
50
|
-
:xexample,
|
51
|
-
:xit,
|
52
|
-
:xspecify
|
53
|
-
].each do |name|
|
54
|
-
module_eval(<<-END_RUBY, __FILE__, __LINE__)
|
55
|
-
def #{name}(desc=nil, *args, &block)
|
56
|
-
example_method(:#{name}, desc, *args, &block)
|
57
|
-
end
|
58
|
-
END_RUBY
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
module ExampleGroupMethods
|
63
|
-
def spy(&block)
|
64
|
-
setup_spy_hook
|
65
|
-
|
66
|
-
proxy = SpyProxy.new(self)
|
67
|
-
proxy.instance_eval(&block)
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
def setup_spy_hook
|
72
|
-
return if @spy_hook_setup
|
73
|
-
|
74
|
-
let(:__spy__) {}
|
75
|
-
hook = RSpec::Core::Hooks::BeforeHook.new({}) do
|
76
|
-
__spy__
|
77
|
-
end
|
78
|
-
|
79
|
-
hooks[:before][:each].unshift hook
|
80
|
-
@spy_hook_setup = true
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
RSpec::Core::ExampleGroup.class_eval do
|
87
|
-
include RSpec::Spy
|
88
|
-
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# By putting this in lib/rspec/core it gets removed from the example file/line
|
2
|
+
# search so it can find a matching line from the backtrace
|
3
|
+
module RSpec
|
4
|
+
module Core
|
5
|
+
class SpyProxy
|
6
|
+
def initialize(example_group)
|
7
|
+
@example_group = example_group
|
8
|
+
end
|
9
|
+
|
10
|
+
def example_method(method, description, *args, &block)
|
11
|
+
@example_group.context do
|
12
|
+
let(:spy_setup) do
|
13
|
+
RSpec::Spy.in_spy_setup = true
|
14
|
+
instance_eval &block
|
15
|
+
RSpec::Spy.in_spy_setup = false
|
16
|
+
end
|
17
|
+
|
18
|
+
send(method, description, *args) do
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
[
|
24
|
+
:example,
|
25
|
+
:it,
|
26
|
+
:specify,
|
27
|
+
:focused,
|
28
|
+
:focus,
|
29
|
+
:pending,
|
30
|
+
:xexample,
|
31
|
+
:xit,
|
32
|
+
:xspecify
|
33
|
+
].each do |name|
|
34
|
+
module_eval(<<-END_RUBY, __FILE__, __LINE__)
|
35
|
+
def #{name}(desc=nil, *args, &block)
|
36
|
+
example_method(:#{name}, desc, *args, &block)
|
37
|
+
end
|
38
|
+
END_RUBY
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
data/lib/rspec/spy.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Spy
|
3
|
+
class << self
|
4
|
+
attr_accessor :in_spy_setup
|
5
|
+
attr_accessor :strict_mode
|
6
|
+
alias_method :in_spy_setup?, :in_spy_setup
|
7
|
+
alias_method :strict_mode?, :strict_mode
|
8
|
+
|
9
|
+
def ok_to_spy?
|
10
|
+
return true unless strict_mode?
|
11
|
+
in_spy_setup?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rspec/core/spy_proxy'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Spy
|
5
|
+
module ExampleGroupMethods
|
6
|
+
def spy(&block)
|
7
|
+
proxy = RSpec::Core::SpyProxy.new(self)
|
8
|
+
|
9
|
+
if block
|
10
|
+
proxy.instance_eval(&block)
|
11
|
+
else
|
12
|
+
proxy
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec::Core::ExampleGroup.extend RSpec::Spy::ExampleGroupMethods
|
20
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rspec/mocks'
|
2
|
+
|
3
|
+
RSpec::Mocks::Methods.class_eval do
|
4
|
+
def should_receive_with_spy_check(message, opts={}, &block)
|
5
|
+
spy_check(:should_receive)
|
6
|
+
__mock_proxy.add_message_expectation(opts[:expected_from] || caller(1)[0], message.to_sym, opts, &block)
|
7
|
+
end
|
8
|
+
|
9
|
+
def should_not_receive_with_spy_check(message, &block)
|
10
|
+
spy_check(:should_not_receive)
|
11
|
+
__mock_proxy.add_negative_message_expectation(caller(1)[0], message.to_sym, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
alias_method :should_receive!, :should_receive
|
15
|
+
alias_method :should_receive, :should_receive_with_spy_check
|
16
|
+
|
17
|
+
alias_method :should_not_receive!, :should_not_receive
|
18
|
+
alias_method :should_not_receive, :should_not_receive_with_spy_check
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def spy_check(method)
|
23
|
+
return if RSpec::Spy.ok_to_spy?
|
24
|
+
raise "#{method} should not be used outside of a spy block. Please put it in a spy block or use #{method}!."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
data/rspec-spy.gemspec
CHANGED
data/spec/rspec_spy_spec.rb
CHANGED
@@ -7,6 +7,8 @@ class Subject
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
+
RSpec::Spy.strict_mode = true
|
11
|
+
|
10
12
|
describe RSpec::Spy do
|
11
13
|
let(:collaborator) { stub.as_null_object }
|
12
14
|
|
@@ -28,6 +30,20 @@ describe RSpec::Spy do
|
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
33
|
+
spy do
|
34
|
+
specify "should work with specify" do
|
35
|
+
collaborator.should_receive :message
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe RSpec::Spy do
|
41
|
+
let(:collaborator) { stub.as_null_object }
|
42
|
+
|
43
|
+
before do
|
44
|
+
Subject.new.go(collaborator)
|
45
|
+
end
|
46
|
+
|
31
47
|
context do
|
32
48
|
spy do
|
33
49
|
it "should work in nested contexts" do
|
@@ -35,10 +51,38 @@ describe RSpec::Spy do
|
|
35
51
|
end
|
36
52
|
end
|
37
53
|
end
|
54
|
+
end
|
38
55
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
56
|
+
describe RSpec::Spy, "the old way" do
|
57
|
+
let(:collaborator) { stub.as_null_object }
|
58
|
+
|
59
|
+
before do
|
60
|
+
collaborator.should_receive! :message
|
61
|
+
collaborator.should_not_receive! :message2
|
62
|
+
Subject.new.go(collaborator)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should still work" do
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe RSpec::Spy, "should_receive outside of spy block" do
|
70
|
+
let(:collaborator) { stub.as_null_object }
|
71
|
+
|
72
|
+
it "should warn" do
|
73
|
+
lambda { collaborator.should_receive :message }.should raise_error
|
74
|
+
lambda { collaborator.should_not_receive :message }.should raise_error
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe RSpec::Spy, "shorthand" do
|
79
|
+
let(:collaborator) { stub.as_null_object }
|
80
|
+
|
81
|
+
before do
|
82
|
+
Subject.new.go(collaborator)
|
83
|
+
end
|
84
|
+
|
85
|
+
spy.it "should work in nested contexts" do
|
86
|
+
collaborator.should_receive :message
|
43
87
|
end
|
44
88
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-spy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-03
|
12
|
+
date: 2012-04-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70351465973020 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '2.0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70351465973020
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec-mocks
|
27
|
-
requirement: &
|
27
|
+
requirement: &70351465972520 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: '2.0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70351465972520
|
36
36
|
description: Enables AAA testing for rspec-mock
|
37
37
|
email:
|
38
38
|
- aaronjensen@gmail.com
|
@@ -48,7 +48,11 @@ files:
|
|
48
48
|
- README.md
|
49
49
|
- Rakefile
|
50
50
|
- lib/rspec-spy.rb
|
51
|
-
- lib/rspec
|
51
|
+
- lib/rspec/core/spy_proxy.rb
|
52
|
+
- lib/rspec/spy.rb
|
53
|
+
- lib/rspec/spy/example_group_methods.rb
|
54
|
+
- lib/rspec/spy/mock_methods.rb
|
55
|
+
- lib/rspec/spy/version.rb
|
52
56
|
- rspec-spy.gemspec
|
53
57
|
- spec/rspec_spy_spec.rb
|
54
58
|
- spec/spec_helper.rb
|
@@ -75,7 +79,7 @@ rubyforge_project:
|
|
75
79
|
rubygems_version: 1.8.17
|
76
80
|
signing_key:
|
77
81
|
specification_version: 3
|
78
|
-
summary: rspec-spy-0.0.
|
82
|
+
summary: rspec-spy-0.0.2
|
79
83
|
test_files:
|
80
84
|
- spec/rspec_spy_spec.rb
|
81
85
|
- spec/spec_helper.rb
|