bogus 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile.lock +19 -1
  3. data/Guardfile +0 -7
  4. data/Guardfile.cucumber +9 -0
  5. data/README.md +42 -6
  6. data/bogus.gemspec +3 -0
  7. data/features/.nav +5 -2
  8. data/features/authors.md +10 -2
  9. data/features/changelog.md +11 -0
  10. data/features/configuration/fake_ar_attributes.feature +51 -0
  11. data/features/configuration/readme.md +7 -0
  12. data/features/{configuration_options.feature → configuration/search_modules.feature} +2 -2
  13. data/features/fakes/anonymous_doubles.feature +11 -7
  14. data/features/fakes/fake_objects.feature +0 -16
  15. data/lib/bogus/active_record_accessors.rb +41 -0
  16. data/lib/bogus/class_methods.rb +1 -1
  17. data/lib/bogus/configuration.rb +1 -0
  18. data/lib/bogus/constructor_methods.rb +18 -0
  19. data/lib/bogus/copies_methods.rb +7 -5
  20. data/lib/bogus/creates_fakes.rb +1 -1
  21. data/lib/bogus/creates_fakes_with_stubbed_methods.rb +1 -1
  22. data/lib/bogus/ensures_all_interactions_satisfied.rb +0 -2
  23. data/lib/bogus/fake.rb +8 -0
  24. data/lib/bogus/injector.rb +10 -0
  25. data/lib/bogus/instance_methods.rb +1 -1
  26. data/lib/bogus/interaction.rb +22 -3
  27. data/lib/bogus/interaction_presenter.rb +1 -1
  28. data/lib/bogus/makes_ducks.rb +5 -6
  29. data/lib/bogus/makes_subtypes.rb +1 -1
  30. data/lib/bogus/method_stringifier.rb +16 -8
  31. data/lib/bogus/record_interactions.rb +1 -1
  32. data/lib/bogus/records_double_interactions.rb +8 -7
  33. data/lib/bogus/registers_created_fakes.rb +10 -8
  34. data/lib/bogus/responds_to_everything.rb +8 -1
  35. data/lib/bogus/shadow.rb +3 -2
  36. data/lib/bogus/undefined_return_value.rb +11 -0
  37. data/lib/bogus/verifies_contracts.rb +12 -10
  38. data/lib/bogus/verifies_stub_definition.rb +37 -41
  39. data/lib/bogus/version.rb +1 -1
  40. data/spec/bogus/copies_classes_spec.rb +13 -6
  41. data/spec/bogus/creates_fakes_spec.rb +1 -1
  42. data/spec/bogus/fake_ar_attributes_spec.rb +72 -0
  43. data/spec/bogus/faking_factories_spec.rb +83 -0
  44. data/spec/bogus/frozen_fakes_spec.rb +59 -0
  45. data/spec/bogus/interaction_spec.rb +4 -0
  46. data/spec/bogus/method_copiers_spec.rb +26 -0
  47. data/spec/bogus/mocking_dsl_spec.rb +7 -3
  48. data/spec/bogus/overwrites_methods_spec.rb +2 -2
  49. data/spec/bogus/record_interactions_spec.rb +1 -1
  50. data/spec/bogus/ruby_2_support_spec.rb +96 -0
  51. data/spec/bogus/shadow_spec.rb +10 -8
  52. data/spec/bogus/verifies_stub_definition_spec.rb +1 -1
  53. data/spec/spec_helper.rb +1 -1
  54. data/spec/support/matchers.rb +3 -0
  55. 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.3)
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" }
@@ -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
- ## What is Bogus?
11
+ ## Example
10
12
 
11
- 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.
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
- Bogus provides facilities to create *fakes* - test doubles that have the same interface as the doubled class.
27
+ describe PostAdder do
28
+ fake(:post_repository)
14
29
 
15
- Another feature of Bogus is *safe stubbing*, which does not allow you to stub methods that don't exist or don't match the signature specified when stubbing.
30
+ it "stores the post" do
31
+ post_adder = PostAdder.new(post_repository)
32
+
33
+ post_adder.add("Bogus is safe!")
16
34
 
17
- A unique feature of Bogus are the *contract tests*, which reduce the need for integrated tests to a minimum by ensuring that the things you stub match how the object really behaves.
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 our (executable) documentation on Relish.][docs]
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
- - configuration_options.feature
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
@@ -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
+ """
@@ -0,0 +1,7 @@
1
+ Bogus can be configured, similarly to many other frameworks with a configure block.
2
+
3
+ Bogus.configure do |c|
4
+ c.search_modules = [Object]
5
+ c.fake_ar_attributes = true
6
+ end
7
+
@@ -1,6 +1,6 @@
1
- Feature: Configuration Options
1
+ Feature: search_modules
2
2
 
3
- Bogus can be configured, similarly to many other frameworks with a configure block. This feature describes the configuration options available.
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 and makes those calls chainable. This way you can spy on methods without stubbing them first.
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. Fakes that mimic an actual class have many more benefits.
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. This can be used for instance to raise errors in stubbed methods.
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 stubbing any method with any parameters" do
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 stubbing any method with any parameters" do
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 stubbing any method with any parameters" do
142
- library.foo.bar("hello").baz.should == library
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
@@ -1,6 +1,6 @@
1
1
  module Bogus
2
2
  class ClassMethods
3
- extend Bogus::Takes
3
+ extend Takes
4
4
  takes :klass
5
5
 
6
6
  def all
@@ -1,6 +1,7 @@
1
1
  module Bogus
2
2
  class Configuration
3
3
  attr_writer :search_modules
4
+ attr_accessor :fake_ar_attributes
4
5
 
5
6
  def search_modules
6
7
  @search_modules ||= [Object]