bogus 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile.lock +19 -1
- data/Guardfile +0 -7
- data/Guardfile.cucumber +9 -0
- data/README.md +42 -6
- data/bogus.gemspec +3 -0
- data/features/.nav +5 -2
- data/features/authors.md +10 -2
- data/features/changelog.md +11 -0
- data/features/configuration/fake_ar_attributes.feature +51 -0
- data/features/configuration/readme.md +7 -0
- data/features/{configuration_options.feature → configuration/search_modules.feature} +2 -2
- data/features/fakes/anonymous_doubles.feature +11 -7
- data/features/fakes/fake_objects.feature +0 -16
- data/lib/bogus/active_record_accessors.rb +41 -0
- data/lib/bogus/class_methods.rb +1 -1
- data/lib/bogus/configuration.rb +1 -0
- data/lib/bogus/constructor_methods.rb +18 -0
- data/lib/bogus/copies_methods.rb +7 -5
- data/lib/bogus/creates_fakes.rb +1 -1
- data/lib/bogus/creates_fakes_with_stubbed_methods.rb +1 -1
- data/lib/bogus/ensures_all_interactions_satisfied.rb +0 -2
- data/lib/bogus/fake.rb +8 -0
- data/lib/bogus/injector.rb +10 -0
- data/lib/bogus/instance_methods.rb +1 -1
- data/lib/bogus/interaction.rb +22 -3
- data/lib/bogus/interaction_presenter.rb +1 -1
- data/lib/bogus/makes_ducks.rb +5 -6
- data/lib/bogus/makes_subtypes.rb +1 -1
- data/lib/bogus/method_stringifier.rb +16 -8
- data/lib/bogus/record_interactions.rb +1 -1
- data/lib/bogus/records_double_interactions.rb +8 -7
- data/lib/bogus/registers_created_fakes.rb +10 -8
- data/lib/bogus/responds_to_everything.rb +8 -1
- data/lib/bogus/shadow.rb +3 -2
- data/lib/bogus/undefined_return_value.rb +11 -0
- data/lib/bogus/verifies_contracts.rb +12 -10
- data/lib/bogus/verifies_stub_definition.rb +37 -41
- data/lib/bogus/version.rb +1 -1
- data/spec/bogus/copies_classes_spec.rb +13 -6
- data/spec/bogus/creates_fakes_spec.rb +1 -1
- data/spec/bogus/fake_ar_attributes_spec.rb +72 -0
- data/spec/bogus/faking_factories_spec.rb +83 -0
- data/spec/bogus/frozen_fakes_spec.rb +59 -0
- data/spec/bogus/interaction_spec.rb +4 -0
- data/spec/bogus/method_copiers_spec.rb +26 -0
- data/spec/bogus/mocking_dsl_spec.rb +7 -3
- data/spec/bogus/overwrites_methods_spec.rb +2 -2
- data/spec/bogus/record_interactions_spec.rb +1 -1
- data/spec/bogus/ruby_2_support_spec.rb +96 -0
- data/spec/bogus/shadow_spec.rb +10 -8
- data/spec/bogus/verifies_stub_definition_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/support/matchers.rb +3 -0
- metadata +76 -66
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 45d3e04ef1d759f2ae6cb447d108e2b49c933e28
|
4
|
+
data.tar.gz: c2339f094723ca2fd84119abfa1c76091a4fd859
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6012c4513cfd50e490a50c4487305b547074dd759f28b61fbea9dd2ebd09f40bad12f4ce70cf18357b6048822bfb9af6939eb7891155b1a4749fc763ffc9487d
|
7
|
+
data.tar.gz: 855a276e95ea62f1fa9dbcb5c6934b6a342aa6adadc4b16e919d67ce12c087960db297ff919169214529659eedcea9e6ad9c7d3c653a4261f4495d25d63257d7
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,27 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
bogus (0.0
|
4
|
+
bogus (0.1.0)
|
5
5
|
dependor (>= 0.0.4)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: http://rubygems.org/
|
9
9
|
specs:
|
10
|
+
activemodel (3.2.13)
|
11
|
+
activesupport (= 3.2.13)
|
12
|
+
builder (~> 3.0.0)
|
13
|
+
activerecord (3.2.13)
|
14
|
+
activemodel (= 3.2.13)
|
15
|
+
activesupport (= 3.2.13)
|
16
|
+
arel (~> 3.0.2)
|
17
|
+
tzinfo (~> 0.3.29)
|
18
|
+
activerecord-nulldb-adapter (0.2.3)
|
19
|
+
activerecord (>= 2.0.0)
|
20
|
+
activesupport (3.2.13)
|
21
|
+
i18n (= 0.6.1)
|
22
|
+
multi_json (~> 1.0)
|
10
23
|
archive-tar-minitar (0.5.2)
|
24
|
+
arel (3.0.2)
|
11
25
|
aruba (0.4.11)
|
12
26
|
childprocess (>= 0.2.3)
|
13
27
|
cucumber (>= 1.1.1)
|
@@ -44,6 +58,7 @@ GEM
|
|
44
58
|
guard (>= 1.1.0)
|
45
59
|
guard-rspec (1.1.0)
|
46
60
|
guard (>= 1.1)
|
61
|
+
i18n (0.6.1)
|
47
62
|
json (1.7.3)
|
48
63
|
libnotify (0.7.4)
|
49
64
|
ffi (~> 1.0.11)
|
@@ -79,11 +94,14 @@ GEM
|
|
79
94
|
simplecov-html (~> 0.7.1)
|
80
95
|
simplecov-html (0.7.1)
|
81
96
|
thor (0.15.3)
|
97
|
+
tzinfo (0.3.37)
|
82
98
|
|
83
99
|
PLATFORMS
|
84
100
|
ruby
|
85
101
|
|
86
102
|
DEPENDENCIES
|
103
|
+
activerecord
|
104
|
+
activerecord-nulldb-adapter
|
87
105
|
aruba
|
88
106
|
bogus!
|
89
107
|
coveralls
|
data/Guardfile
CHANGED
@@ -1,13 +1,6 @@
|
|
1
1
|
# A sample Guardfile
|
2
2
|
# More info at https://github.com/guard/guard#readme
|
3
3
|
|
4
|
-
guard 'cucumber' do
|
5
|
-
watch(%r{^features/.+\.feature$})
|
6
|
-
watch(%r{^features/support/.+$}) { 'features' }
|
7
|
-
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
8
|
-
#watch(%r{^lib/(.+)\.rb$}) { 'features' }
|
9
|
-
end
|
10
|
-
|
11
4
|
guard 'rspec', :version => 2 do
|
12
5
|
watch(%r{^spec/.+_spec\.rb$})
|
13
6
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
data/Guardfile.cucumber
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'cucumber' do
|
5
|
+
watch(%r{^features/.+\.feature$})
|
6
|
+
watch(%r{^features/support/.+$}) { 'features' }
|
7
|
+
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
8
|
+
watch(%r{^lib/(.+)\.rb$}) { 'features' }
|
9
|
+
end
|
data/README.md
CHANGED
@@ -1,24 +1,53 @@
|
|
1
1
|
# Bogus
|
2
2
|
|
3
|
+
Bogus aims to make your unit tests more reliable by ensuring that you don't stub or mock methods that don't actually exist in the mocked objects.
|
4
|
+
|
3
5
|
[![build status](https://secure.travis-ci.org/psyho/bogus.png)](http://travis-ci.org/psyho/bogus)
|
4
6
|
[![Code Climate](https://codeclimate.com/github/psyho/bogus.png)](https://codeclimate.com/github/psyho/bogus)
|
5
7
|
[![Coverage Status](https://coveralls.io/repos/psyho/bogus/badge.png?branch=master)](https://coveralls.io/r/psyho/bogus?branch=master)
|
6
8
|
[![Gem Version](https://badge.fury.io/rb/bogus.png)](http://badge.fury.io/rb/bogus)
|
7
9
|
[![Dependency Status](https://gemnasium.com/psyho/bogus.png)](https://gemnasium.com/psyho/bogus)
|
8
10
|
|
9
|
-
##
|
11
|
+
## Example
|
10
12
|
|
11
|
-
|
13
|
+
```ruby
|
14
|
+
class PostRepository
|
15
|
+
def store(title)
|
16
|
+
# save a new post in the database
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class PostAdder < Struct.new(:post_repository)
|
21
|
+
def add(title)
|
22
|
+
post = post_repository.store(title)
|
23
|
+
# do some stuff with the post
|
24
|
+
end
|
25
|
+
end
|
12
26
|
|
13
|
-
|
27
|
+
describe PostAdder do
|
28
|
+
fake(:post_repository)
|
14
29
|
|
15
|
-
|
30
|
+
it "stores the post" do
|
31
|
+
post_adder = PostAdder.new(post_repository)
|
32
|
+
|
33
|
+
post_adder.add("Bogus is safe!")
|
16
34
|
|
17
|
-
|
35
|
+
post_repository.should have_received.store("Bogus is safe!")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
## Features
|
41
|
+
|
42
|
+
* [Safe Stubbing][safe-stubbing] - Bogus does not allow you to stub methods that don't exist or don't match the stubbed signature.
|
43
|
+
* [Fakes][fakes] - test doubles that have the same interface as the doubled class.
|
44
|
+
* [Support for ActiveRecord models][ar-support] - Bogus comes with support for active record fields out of the box.
|
45
|
+
* [Global fake configuration][global-configuration] - Decouple your fakes from class names and define default return values in one place.
|
46
|
+
* [Contract tests][contract-tests] - a unique feature of Bogus, which reduces the need for integrated tests to a minimum by ensuring that the things you stub match how the object really behaves.
|
18
47
|
|
19
48
|
## Documentation
|
20
49
|
|
21
|
-
[You can find
|
50
|
+
[You can find more detailed (and executable) documentation on Relish.][docs]
|
22
51
|
|
23
52
|
## License
|
24
53
|
|
@@ -28,6 +57,13 @@ MIT. See the LICENSE file.
|
|
28
57
|
|
29
58
|
* [Adam Pohorecki](http://github.com/psyho)
|
30
59
|
* [Paweł Pierzchała](http://github.com/wrozka)
|
60
|
+
* [Piotr Szotkowski](https://github.com/chastell)
|
31
61
|
* [Marek Nowak](https://github.com/yundt)
|
32
62
|
|
33
63
|
[docs]: http://www.relishapp.com/bogus/bogus/docs
|
64
|
+
|
65
|
+
[safe-stubbing]: https://www.relishapp.com/bogus/bogus/docs/safe-stubbing
|
66
|
+
[fakes]: https://www.relishapp.com/bogus/bogus/docs/fakes
|
67
|
+
[ar-support]: https://www.relishapp.com/bogus/bogus/docs/configuration/fake-ar-attributes
|
68
|
+
[global-configuration]: https://www.relishapp.com/bogus/bogus/docs/fakes/global-fake-configuration
|
69
|
+
[contract-tests]: https://www.relishapp.com/bogus/bogus/docs/contract-tests
|
data/bogus.gemspec
CHANGED
@@ -34,4 +34,7 @@ Gem::Specification.new do |s|
|
|
34
34
|
s.add_development_dependency 'rr'
|
35
35
|
s.add_development_dependency 'relish'
|
36
36
|
s.add_development_dependency 'coveralls'
|
37
|
+
|
38
|
+
s.add_development_dependency 'activerecord'
|
39
|
+
s.add_development_dependency 'activerecord-nulldb-adapter'
|
37
40
|
end
|
data/features/.nav
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
- getting_started.md (Getting Started)
|
2
2
|
- readme.md (Introduction to Bogus)
|
3
|
-
- changelog.md
|
4
3
|
- fakes (Fakes):
|
5
4
|
- fake_objects.feature
|
6
5
|
- global_fake_configuration.feature
|
@@ -12,11 +11,15 @@
|
|
12
11
|
- safe_stubbing.feature
|
13
12
|
- spies.feature
|
14
13
|
- argument_matchers.feature
|
14
|
+
- active_record.feature
|
15
15
|
- contract_tests (Contract Tests):
|
16
16
|
- contract_tests_mocks.feature
|
17
17
|
- contract_tests_stubs.feature
|
18
18
|
- contract_tests_spies.feature
|
19
19
|
- return_value_contracts.feature
|
20
|
-
-
|
20
|
+
- configuration (Configuration Options):
|
21
|
+
- search_modules.feature
|
22
|
+
- fake_ar_attributes.feature
|
23
|
+
- changelog.md
|
21
24
|
- license.md
|
22
25
|
- authors.md
|
data/features/authors.md
CHANGED
@@ -9,10 +9,15 @@ blog: [adam.pohorecki.pl][blog]
|
|
9
9
|
github: [wrozka][wrozka]
|
10
10
|
twitter: [@zwrozka][zwrozka]
|
11
11
|
|
12
|
+
## Piotr Szotkowski
|
13
|
+
|
14
|
+
github: [chastell][chastell]
|
15
|
+
twitter: [@chastell][chastell-twitter]
|
16
|
+
|
12
17
|
## Marek Nowak
|
13
18
|
|
14
19
|
github: [yundt][yundt]
|
15
|
-
twitter: [@yundt][yundt]
|
20
|
+
twitter: [@yundt][yundt-twitter]
|
16
21
|
|
17
22
|
## Contract tests
|
18
23
|
|
@@ -35,8 +40,11 @@ The development of Bogus was partially sponsored by [Lunar Logic][llp].
|
|
35
40
|
[wrozka]: https://github.com/wrozka
|
36
41
|
[zwrozka]: http://twitter.com/zwrozka
|
37
42
|
|
43
|
+
[chastell]: https://github.com/chastell
|
44
|
+
[chastell-twitter]: http://twitter.com/chastell
|
45
|
+
|
38
46
|
[yundt]: https://github.com/yundt
|
39
|
-
[yundt]: http://twitter.com/yundt
|
47
|
+
[yundt-twitter]: http://twitter.com/yundt
|
40
48
|
|
41
49
|
[scam]: http://www.infoq.com/presentations/integration-tests-scam
|
42
50
|
[rr]: https://github.com/btakita/rr
|
data/features/changelog.md
CHANGED
@@ -27,3 +27,14 @@ Initial version.
|
|
27
27
|
|
28
28
|
- Support mocking methods with optional parameters
|
29
29
|
|
30
|
+
## 0.1.0 (in progress)
|
31
|
+
|
32
|
+
- Support for stubbing on frozen fakes
|
33
|
+
- Safe stubbing of constructors
|
34
|
+
- Fixed spying on anonymous fakes
|
35
|
+
- Automatic handling of ActiveRecord columns
|
36
|
+
- Support Ruby 2.0 keyword arguments
|
37
|
+
|
38
|
+
### Breaking changes:
|
39
|
+
|
40
|
+
- Fakes no longer return themselves from unstubbed method calls, because this was often a source of confusion. In the new version we return a Bogus::UndefinedReturnValue which contains the method name and arguments from where it was returned.
|
@@ -0,0 +1,51 @@
|
|
1
|
+
Feature: fake_ar_attributes
|
2
|
+
|
3
|
+
Instances of ActiveRecord::Base subclasses are different then most of the objects you might encounter because the field access on those classes is done by taking advantage of Ruby's `method_missing` functionality.
|
4
|
+
|
5
|
+
Unfortunately, in order to create a fake, Bogus has to examine all of the methods that are defined on a given class and herein lies the problem, the methods that you would expect to have on your ActiveRecord models do not exist:
|
6
|
+
|
7
|
+
class BlogPost < ActiveRecord::Base
|
8
|
+
end
|
9
|
+
|
10
|
+
blog_post = BlogPost.new
|
11
|
+
blog_post.respond_to?(:name) # => true
|
12
|
+
blog_post.method(:name) # raises NameError
|
13
|
+
|
14
|
+
Normally, this would prevent Bogus from being able to fake those methods, but in the case of ActiveRecord we can figure out those fields by looking at the `BlogPost.columns` property. Based on that we can define those accessors on the created fake. If you wish to take advantage of that, you just need to flip a configuration switch:
|
15
|
+
|
16
|
+
Bogus.configure do |c|
|
17
|
+
c.fake_ar_attributes = true
|
18
|
+
end
|
19
|
+
|
20
|
+
Scenario: Adding missing accessors to AR classes
|
21
|
+
Given a file named "foo.rb" with:
|
22
|
+
"""ruby
|
23
|
+
require 'active_record'
|
24
|
+
require 'nulldb'
|
25
|
+
|
26
|
+
ActiveRecord::Schema.verbose = false
|
27
|
+
ActiveRecord::Base.establish_connection :adapter => :nulldb
|
28
|
+
|
29
|
+
ActiveRecord::Schema.define do
|
30
|
+
create_table :blog_posts do |t|
|
31
|
+
t.string :name
|
32
|
+
t.string :tags
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class BlogPost < ActiveRecord::Base
|
37
|
+
end
|
38
|
+
|
39
|
+
Bogus.configure do |c|
|
40
|
+
c.fake_ar_attributes = true
|
41
|
+
end
|
42
|
+
"""
|
43
|
+
|
44
|
+
Then the following test should pass:
|
45
|
+
"""ruby
|
46
|
+
post = fake(:blog_post, name: "the name")
|
47
|
+
stub(post).tags { "foo, bar" }
|
48
|
+
|
49
|
+
post.name.should == "the name"
|
50
|
+
post.tags.should == "foo, bar"
|
51
|
+
"""
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Feature:
|
1
|
+
Feature: search_modules
|
2
2
|
|
3
|
-
|
3
|
+
Most projects do not have a separate namespace for their classes, which the default that Bogus assumes. However, if all (or some) of your classes exist within some module you can add it to the list of modules that Bogus will look in when trying to resolve class names.
|
4
4
|
|
5
5
|
Scenario: search_modules
|
6
6
|
Given a file named "foo.rb" with:
|
@@ -2,15 +2,15 @@ Feature: Anonymous test doubles
|
|
2
2
|
|
3
3
|
Anonymous test doubles can be useful as a stepping stone towards actual fakes and when migrating from another testing library.
|
4
4
|
|
5
|
-
In contrast with other testing libraries, Bogus makes its fakes respond to all methods by default
|
5
|
+
In contrast with other testing libraries, Bogus makes its fakes respond to all methods by default. This way you can spy on methods without stubbing them first.
|
6
6
|
|
7
|
-
It is not advisable to use those for anything else than an intermediate step.
|
7
|
+
It is not advisable to use those for anything else than an intermediate step. Fakes that mimic an actual class have many more benefits.
|
8
8
|
|
9
9
|
The syntax for defining fakes is:
|
10
10
|
|
11
11
|
fake(method_1: return_value, method_2: proc{return_value2})
|
12
12
|
|
13
|
-
If you pass a proc as a return value to a fake, the proc will be called to obtain the value.
|
13
|
+
If you pass a proc as a return value to a fake, the proc will be called to obtain the value. This can be used for instance to raise errors in stubbed methods.
|
14
14
|
|
15
15
|
If you want to actually return a proc from a method, you need to use a slightly longer syntax:
|
16
16
|
|
@@ -81,7 +81,7 @@ Feature: Anonymous test doubles
|
|
81
81
|
let(:library) { fake }
|
82
82
|
let(:jake) { Student.new("Jake") }
|
83
83
|
|
84
|
-
it "allows
|
84
|
+
it "allows mocking any method with any parameters" do
|
85
85
|
mock(library).register_junior("Jake") { "the card" }
|
86
86
|
|
87
87
|
jake.sign_up(library)
|
@@ -124,7 +124,7 @@ Feature: Anonymous test doubles
|
|
124
124
|
let(:library) { fake }
|
125
125
|
let(:jake) { Student.new("Jake") }
|
126
126
|
|
127
|
-
it "allows
|
127
|
+
it "allows spying on any method" do
|
128
128
|
jake.sign_up(library)
|
129
129
|
|
130
130
|
library.should have_received.register_junior("Jake")
|
@@ -138,8 +138,12 @@ Feature: Anonymous test doubles
|
|
138
138
|
describe Student do
|
139
139
|
let(:library) { fake }
|
140
140
|
|
141
|
-
it "allows
|
142
|
-
|
141
|
+
it "allows calling any method with any parameters" do
|
142
|
+
expect {
|
143
|
+
library.foo
|
144
|
+
library.bar("hello")
|
145
|
+
library.baz(1, 2, 3, 4, 5)
|
146
|
+
}.not_to raise_error
|
143
147
|
end
|
144
148
|
end
|
145
149
|
"""
|
@@ -59,22 +59,6 @@ Feature: Faking existing classes
|
|
59
59
|
end
|
60
60
|
"""
|
61
61
|
|
62
|
-
Scenario: Fakes have null-object semantics
|
63
|
-
Then spec file with following content should pass:
|
64
|
-
"""ruby
|
65
|
-
describe "library fake" do
|
66
|
-
fake(:library)
|
67
|
-
|
68
|
-
it "returns self from all methods" do
|
69
|
-
library.checkout("hello").should == library
|
70
|
-
end
|
71
|
-
|
72
|
-
it "makes method chaining possible" do
|
73
|
-
library.checkout("hello").return_book("world").should == library
|
74
|
-
end
|
75
|
-
end
|
76
|
-
"""
|
77
|
-
|
78
62
|
Scenario: Taking the guesswork out of finding a class to copy
|
79
63
|
Then spec file with following content should pass:
|
80
64
|
"""ruby
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Bogus
|
4
|
+
class ActiveRecordAccessors
|
5
|
+
extend Takes
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
takes :klass, :instance_methods
|
9
|
+
|
10
|
+
def_delegators :instance_methods, :remove, :define
|
11
|
+
|
12
|
+
def all
|
13
|
+
return [] unless klass < ActiveRecord::Base
|
14
|
+
return missing_attributes
|
15
|
+
end
|
16
|
+
|
17
|
+
def get(name)
|
18
|
+
Attribute.new(name)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def instance_methods
|
24
|
+
@instance_methods.call(klass)
|
25
|
+
end
|
26
|
+
|
27
|
+
def all_attributes
|
28
|
+
klass.columns.map(&:name).map(&:to_sym)
|
29
|
+
end
|
30
|
+
|
31
|
+
def missing_attributes
|
32
|
+
all_attributes - instance_methods.all
|
33
|
+
end
|
34
|
+
|
35
|
+
class Attribute < Struct.new(:name)
|
36
|
+
def parameters
|
37
|
+
[]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/bogus/class_methods.rb
CHANGED