bogus 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -0
- data/Gemfile.lock +6 -1
- data/README.md +3 -0
- data/features/changelog.md +30 -22
- data/features/configuration/fake_ar_attributes.feature +3 -1
- data/features/configuration/search_modules.feature +5 -0
- data/features/contract_tests/contract_tests_mocks.feature +12 -1
- data/features/contract_tests/contract_tests_spies.feature +14 -2
- data/features/contract_tests/contract_tests_stubs.feature +13 -2
- data/features/contract_tests/return_value_contracts.feature +15 -4
- data/features/fakes/anonymous_doubles.feature +15 -1
- data/features/fakes/duck_types.feature +12 -2
- data/features/fakes/fake_objects.feature +11 -1
- data/features/fakes/global_fake_configuration.feature +4 -1
- data/features/readme.md +2 -2
- data/features/safe_stubbing/argument_matchers.feature +32 -2
- data/features/safe_stubbing/safe_mocking.feature +9 -2
- data/features/safe_stubbing/safe_stubbing.feature +11 -2
- data/features/safe_stubbing/spies.feature +52 -1
- data/features/step_definitions/rspec_steps.rb +1 -2
- data/features/support/env.rb +19 -0
- data/lib/bogus/active_record_accessors.rb +4 -4
- data/lib/bogus/adds_recording.rb +1 -0
- data/lib/bogus/any_args.rb +32 -3
- data/lib/bogus/class_methods.rb +7 -1
- data/lib/bogus/copies_classes.rb +5 -2
- data/lib/bogus/fake.rb +0 -2
- data/lib/bogus/have_received_matcher.rb +5 -0
- data/lib/bogus/interaction.rb +66 -35
- data/lib/bogus/interactions_repository.rb +1 -1
- data/lib/bogus/makes_substitute_methods.rb +3 -2
- data/lib/bogus/mocking_dsl.rb +8 -0
- data/lib/bogus/public_methods.rb +1 -1
- data/lib/bogus/rspec_extensions.rb +8 -1
- data/lib/bogus/same_class.rb +14 -0
- data/lib/bogus/shadow.rb +8 -12
- data/lib/bogus/verifies_stub_definition.rb +1 -5
- data/lib/bogus/version.rb +1 -1
- data/spec/bogus/adds_recording_spec.rb +8 -0
- data/spec/bogus/class_methods_spec.rb +8 -2
- data/spec/bogus/clean_ruby_spec.rb +15 -0
- data/spec/bogus/have_received_matcher_spec.rb +45 -27
- data/spec/bogus/instance_methods_spec.rb +1 -1
- data/spec/bogus/interaction_spec.rb +87 -83
- data/spec/bogus/interactions_repository_spec.rb +8 -11
- data/spec/bogus/shadow_spec.rb +4 -1
- metadata +81 -39
- checksums.yaml +0 -7
@@ -21,7 +21,7 @@ Feature: Faking duck types
|
|
21
21
|
end
|
22
22
|
|
23
23
|
Background:
|
24
|
-
Given a file named "
|
24
|
+
Given a file named "loggers.rb" with:
|
25
25
|
"""ruby
|
26
26
|
class DatabaseLogger
|
27
27
|
def error(message); end
|
@@ -56,6 +56,8 @@ Feature: Faking duck types
|
|
56
56
|
Scenario: Copying instance methods
|
57
57
|
Then spec file with following content should pass:
|
58
58
|
"""ruby
|
59
|
+
require_relative 'loggers'
|
60
|
+
|
59
61
|
describe "make_duck" do
|
60
62
|
let(:duck) { make_duck(DatabaseLogger, NetworkLogger,
|
61
63
|
DevNullLogger) }
|
@@ -94,6 +96,8 @@ Feature: Faking duck types
|
|
94
96
|
Scenario: Faking duck types
|
95
97
|
Then spec file with following content should pass:
|
96
98
|
"""ruby
|
99
|
+
require_relative 'loggers'
|
100
|
+
|
97
101
|
describe "fake with multiple classes" do
|
98
102
|
fake(:logger) { [DatabaseLogger,
|
99
103
|
NetworkLogger,
|
@@ -110,7 +114,7 @@ Feature: Faking duck types
|
|
110
114
|
"""
|
111
115
|
|
112
116
|
Scenario: Globally configured duck types
|
113
|
-
|
117
|
+
Given a file named "fakes.rb" with:
|
114
118
|
"""ruby
|
115
119
|
Bogus.fakes do
|
116
120
|
logger_implementations = proc{ [DatabaseLogger,
|
@@ -119,6 +123,12 @@ Feature: Faking duck types
|
|
119
123
|
|
120
124
|
fake :logger, class: logger_implementations
|
121
125
|
end
|
126
|
+
"""
|
127
|
+
|
128
|
+
Then spec file with following content should pass:
|
129
|
+
"""ruby
|
130
|
+
require_relative 'fakes'
|
131
|
+
require_relative 'loggers'
|
122
132
|
|
123
133
|
describe "fake with multiple classes" do
|
124
134
|
fake(:logger)
|
@@ -26,7 +26,7 @@ Feature: Faking existing classes
|
|
26
26
|
let(:foo) { fake(:foo, bar: "value") }
|
27
27
|
|
28
28
|
Background:
|
29
|
-
Given a file named "
|
29
|
+
Given a file named "library.rb" with:
|
30
30
|
"""ruby
|
31
31
|
class Library
|
32
32
|
def checkout(book)
|
@@ -38,7 +38,10 @@ Feature: Faking existing classes
|
|
38
38
|
def self.look_up(book)
|
39
39
|
end
|
40
40
|
end
|
41
|
+
"""
|
41
42
|
|
43
|
+
Given a file named "student.rb" with:
|
44
|
+
"""ruby
|
42
45
|
class Student
|
43
46
|
def self.learn(library = Library.new)
|
44
47
|
library.checkout("hello world")
|
@@ -50,6 +53,9 @@ Feature: Faking existing classes
|
|
50
53
|
Scenario: Calling methods that exist on real object
|
51
54
|
Then spec file with following content should pass:
|
52
55
|
"""ruby
|
56
|
+
require_relative 'student'
|
57
|
+
require_relative 'library'
|
58
|
+
|
53
59
|
describe Student do
|
54
60
|
fake(:library)
|
55
61
|
|
@@ -79,6 +85,8 @@ Feature: Faking existing classes
|
|
79
85
|
Scenario: Fakes which are classes
|
80
86
|
Then spec file with following content should pass:
|
81
87
|
"""ruby
|
88
|
+
require_relative 'library'
|
89
|
+
|
82
90
|
describe "library class fake" do
|
83
91
|
fake(:library, as: :class)
|
84
92
|
|
@@ -99,6 +107,8 @@ Feature: Faking existing classes
|
|
99
107
|
Scenario: Fakes with inline return values
|
100
108
|
Then spec file with following content should pass:
|
101
109
|
"""ruby
|
110
|
+
require_relative 'library'
|
111
|
+
|
102
112
|
describe "library class fake" do
|
103
113
|
let(:library) { fake(:library, checkout: "checked out",
|
104
114
|
return_book: "returned") }
|
@@ -18,7 +18,7 @@ Feature: Global fake configuration
|
|
18
18
|
in your spec helper, or a file required from it.
|
19
19
|
|
20
20
|
Background:
|
21
|
-
Given a file named "
|
21
|
+
Given a file named "public_library.rb" with:
|
22
22
|
"""ruby
|
23
23
|
class PublicLibrary
|
24
24
|
def self.books_by_author(name)
|
@@ -39,6 +39,7 @@ Feature: Global fake configuration
|
|
39
39
|
Then spec file with following content should pass:
|
40
40
|
"""ruby
|
41
41
|
require_relative "fakes"
|
42
|
+
require_relative "public_library"
|
42
43
|
|
43
44
|
describe "The library fake" do
|
44
45
|
fake(:library)
|
@@ -64,6 +65,7 @@ Feature: Global fake configuration
|
|
64
65
|
Then spec file with following content should pass:
|
65
66
|
"""ruby
|
66
67
|
require_relative "fakes"
|
68
|
+
require_relative "public_library"
|
67
69
|
|
68
70
|
describe "The library fake" do
|
69
71
|
fake(:library, books_by_author: ["Some Book"])
|
@@ -78,6 +80,7 @@ Feature: Global fake configuration
|
|
78
80
|
Then spec file with following content should pass:
|
79
81
|
"""ruby
|
80
82
|
require_relative "fakes"
|
83
|
+
require_relative "public_library"
|
81
84
|
|
82
85
|
describe "The library fake" do
|
83
86
|
it "can be overridden in the helper" do
|
data/features/readme.md
CHANGED
@@ -37,8 +37,8 @@ Bogus makes your test doubles more assertive. They will no longer be too shy to
|
|
37
37
|
Let's reexamine our previous example, this time Bogus-style:
|
38
38
|
|
39
39
|
it "returns the average score" do
|
40
|
-
|
41
|
-
|
40
|
+
scores = fake(:scores, get: [5, 9])
|
41
|
+
students = fake(:students, all: ["John", "Mary"])
|
42
42
|
|
43
43
|
report_card = ReportCard.new(scores, students)
|
44
44
|
|
@@ -3,7 +3,7 @@ Feature: Argument matchers
|
|
3
3
|
Bogus supports some argument matchers for use, when you don't really care about exact equality of arguments passed in or spied on.
|
4
4
|
|
5
5
|
Background:
|
6
|
-
Given a file named "
|
6
|
+
Given a file named "catalog.rb" with:
|
7
7
|
"""ruby
|
8
8
|
class Catalog
|
9
9
|
def self.books_by_author_and_title(author, title)
|
@@ -14,17 +14,47 @@ Feature: Argument matchers
|
|
14
14
|
Scenario: Stubbing methods with any arguments
|
15
15
|
Then the following test should pass:
|
16
16
|
"""ruby
|
17
|
+
require_relative 'catalog'
|
18
|
+
|
17
19
|
stub(Catalog).books_by_author_and_title(any_args) { :some_book }
|
18
20
|
|
19
|
-
Catalog.books_by_author_and_title("
|
21
|
+
Catalog.books_by_author_and_title("Arthur Conan Doyle", "Sherlock Holmes").should == :some_book
|
20
22
|
"""
|
21
23
|
|
22
24
|
Scenario: Stubbing methods with some wildcard arguments
|
23
25
|
Then the following test should pass:
|
24
26
|
"""ruby
|
27
|
+
require_relative 'catalog'
|
28
|
+
|
29
|
+
stub(Catalog).books_by_author_and_title(any_args) { :some_book }
|
25
30
|
stub(Catalog).books_by_author_and_title("Mark Twain", anything) { :twains_book }
|
26
31
|
|
27
32
|
Catalog.books_by_author_and_title("Mark Twain", "Tom Sawyer").should == :twains_book
|
28
33
|
Catalog.books_by_author_and_title("Mark Twain", "Huckleberry Finn").should == :twains_book
|
34
|
+
Catalog.books_by_author_and_title("Arthur Conan Doyle", "Sherlock Holmes").should == :some_book
|
35
|
+
"""
|
36
|
+
|
37
|
+
Scenario: Stubbing methods with proc argument matcher
|
38
|
+
Then the following test should pass:
|
39
|
+
"""ruby
|
40
|
+
require_relative 'catalog'
|
41
|
+
|
42
|
+
stub(Catalog).books_by_author_and_title(any_args) { :some_book }
|
43
|
+
stub(Catalog).books_by_author_and_title(with{|author| author =~ /Twain/ }) { :twains_book }
|
44
|
+
|
45
|
+
Catalog.books_by_author_and_title("Mark Twain", "Tom Sawyer").should == :twains_book
|
46
|
+
Catalog.books_by_author_and_title("M. Twain", "Huckleberry Finn").should == :twains_book
|
47
|
+
Catalog.books_by_author_and_title("Arthur Conan Doyle", "Sherlock Holmes").should == :some_book
|
29
48
|
"""
|
30
49
|
|
50
|
+
Scenario: Stubbing methods with argument type matcher
|
51
|
+
Then the following test should pass:
|
52
|
+
"""ruby
|
53
|
+
require_relative 'catalog'
|
54
|
+
|
55
|
+
stub(Catalog).books_by_author_and_title(any_args) { :some_book }
|
56
|
+
stub(Catalog).books_by_author_and_title(any(String), any(String)) { :twains_book }
|
57
|
+
|
58
|
+
Catalog.books_by_author_and_title("Mark Twain", "Tom Sawyer").should == :twains_book
|
59
|
+
Catalog.books_by_author_and_title("M. Twain", :other_book).should == :some_book
|
60
|
+
"""
|
@@ -15,7 +15,7 @@ Feature: Safe mocking
|
|
15
15
|
You can only mock methods that actually exist on an object. It will also work with methods that the object `responds_to?`, but (obviously) without being able to check the method signature.
|
16
16
|
|
17
17
|
Background:
|
18
|
-
Given a file named "
|
18
|
+
Given a file named "library.rb" with:
|
19
19
|
"""ruby
|
20
20
|
class Library
|
21
21
|
def checkout(book)
|
@@ -26,8 +26,9 @@ Feature: Safe mocking
|
|
26
26
|
Scenario: Mocking methods that exist on real object
|
27
27
|
Then spec file with following content should pass:
|
28
28
|
"""ruby
|
29
|
-
|
29
|
+
require_relative 'library'
|
30
30
|
|
31
|
+
describe Library do
|
31
32
|
it "does something" do
|
32
33
|
library = Library.new
|
33
34
|
mock(library).checkout("some book") { :checked_out }
|
@@ -40,6 +41,8 @@ Feature: Safe mocking
|
|
40
41
|
Scenario: Mocking methods that do not exist on real object
|
41
42
|
Then spec file with following content should fail:
|
42
43
|
"""ruby
|
44
|
+
require_relative 'library'
|
45
|
+
|
43
46
|
describe Library do
|
44
47
|
it "does something" do
|
45
48
|
library = Library.new
|
@@ -52,6 +55,8 @@ Feature: Safe mocking
|
|
52
55
|
Scenario: Mocking methods with wrong number of arguments
|
53
56
|
Then spec file with following content should fail:
|
54
57
|
"""ruby
|
58
|
+
require_relative 'library'
|
59
|
+
|
55
60
|
describe Library do
|
56
61
|
it "does something" do
|
57
62
|
library = Library.new
|
@@ -64,6 +69,8 @@ Feature: Safe mocking
|
|
64
69
|
Scenario: Mocks require the methods to be called
|
65
70
|
Then spec file with following content should fail:
|
66
71
|
"""ruby
|
72
|
+
require_relative 'library'
|
73
|
+
|
67
74
|
describe Library do
|
68
75
|
it "does something" do
|
69
76
|
library = Library.new
|
@@ -7,7 +7,7 @@ Feature: Safe stubbing
|
|
7
7
|
stub(object).method_name(arg1, arg2, ...) { return_value }
|
8
8
|
|
9
9
|
Background:
|
10
|
-
Given a file named "
|
10
|
+
Given a file named "library.rb" with:
|
11
11
|
"""ruby
|
12
12
|
class Library
|
13
13
|
def checkout(book)
|
@@ -18,8 +18,9 @@ Feature: Safe stubbing
|
|
18
18
|
Scenario: Stubbing methods that exist on real object
|
19
19
|
Then spec file with following content should pass:
|
20
20
|
"""ruby
|
21
|
-
|
21
|
+
require_relative 'library'
|
22
22
|
|
23
|
+
describe Library do
|
23
24
|
it "does something" do
|
24
25
|
library = Library.new
|
25
26
|
stub(library).checkout("some book") { :checked_out }
|
@@ -32,6 +33,8 @@ Feature: Safe stubbing
|
|
32
33
|
Scenario: Stubbing methods that do not exist on real object
|
33
34
|
Then spec file with following content should fail:
|
34
35
|
"""ruby
|
36
|
+
require_relative 'library'
|
37
|
+
|
35
38
|
describe Library do
|
36
39
|
it "does something" do
|
37
40
|
library = Library.new
|
@@ -43,6 +46,8 @@ Feature: Safe stubbing
|
|
43
46
|
Scenario: Stubbing methods with wrong number of arguments
|
44
47
|
Then spec file with following content should fail:
|
45
48
|
"""ruby
|
49
|
+
require_relative 'library'
|
50
|
+
|
46
51
|
describe Library do
|
47
52
|
it "does something" do
|
48
53
|
library = Library.new
|
@@ -54,6 +59,8 @@ Feature: Safe stubbing
|
|
54
59
|
Scenario: Stubs allow the methods to be called
|
55
60
|
Then spec file with following content should pass:
|
56
61
|
"""ruby
|
62
|
+
require_relative 'library'
|
63
|
+
|
57
64
|
describe Library do
|
58
65
|
it "does something" do
|
59
66
|
library = Library.new
|
@@ -65,6 +72,8 @@ Feature: Safe stubbing
|
|
65
72
|
Scenario: Stubbing methods multiple times
|
66
73
|
Then spec file with following content should fail:
|
67
74
|
"""ruby
|
75
|
+
require_relative 'library'
|
76
|
+
|
68
77
|
describe Library do
|
69
78
|
it "stubbing with too many arguments" do
|
70
79
|
library = Library.new
|
@@ -5,14 +5,17 @@ Feature: Spies
|
|
5
5
|
Typically, stubbing libraries force you to first stub a method, so that you can later make sure it was called. However, if you use fakes, Bogus lets you verify that a method was called (or not) without stubbing it first.
|
6
6
|
|
7
7
|
Background:
|
8
|
-
Given a file named "
|
8
|
+
Given a file named "library.rb" with:
|
9
9
|
"""ruby
|
10
10
|
class Library
|
11
11
|
def checkout(book)
|
12
12
|
# marks book as checked out
|
13
13
|
end
|
14
14
|
end
|
15
|
+
"""
|
15
16
|
|
17
|
+
Given a file named "student.rb" with:
|
18
|
+
"""ruby
|
16
19
|
class Student
|
17
20
|
def initialize(library)
|
18
21
|
@library = library
|
@@ -29,6 +32,9 @@ Feature: Spies
|
|
29
32
|
Scenario: Ensuring methods were called
|
30
33
|
Then spec file with following content should pass:
|
31
34
|
"""ruby
|
35
|
+
require_relative 'student'
|
36
|
+
require_relative 'library'
|
37
|
+
|
32
38
|
describe Student do
|
33
39
|
fake(:library)
|
34
40
|
|
@@ -46,6 +52,9 @@ Feature: Spies
|
|
46
52
|
Scenario: Spying on methods that do not exist
|
47
53
|
Then spec file with following content should fail:
|
48
54
|
"""ruby
|
55
|
+
require_relative 'student'
|
56
|
+
require_relative 'library'
|
57
|
+
|
49
58
|
describe Student do
|
50
59
|
fake(:library)
|
51
60
|
|
@@ -62,6 +71,9 @@ Feature: Spies
|
|
62
71
|
Scenario: Spying on methods with wrong number of arguments
|
63
72
|
Then spec file with following content should fail:
|
64
73
|
"""ruby
|
74
|
+
require_relative 'student'
|
75
|
+
require_relative 'library'
|
76
|
+
|
65
77
|
describe Student do
|
66
78
|
fake(:library)
|
67
79
|
|
@@ -79,6 +91,9 @@ Feature: Spies
|
|
79
91
|
Scenario: Spying on previously stubbed methods
|
80
92
|
Then spec file with following content should pass:
|
81
93
|
"""ruby
|
94
|
+
require_relative 'student'
|
95
|
+
require_relative 'library'
|
96
|
+
|
82
97
|
describe Student do
|
83
98
|
fake(:library)
|
84
99
|
|
@@ -91,3 +106,39 @@ Feature: Spies
|
|
91
106
|
end
|
92
107
|
end
|
93
108
|
"""
|
109
|
+
|
110
|
+
Scenario: Spying on attribute writers
|
111
|
+
Given a file named "canvas.rb" with:
|
112
|
+
"""ruby
|
113
|
+
class Canvas
|
114
|
+
def background_color=(color)
|
115
|
+
# do something complicated
|
116
|
+
end
|
117
|
+
end
|
118
|
+
"""
|
119
|
+
|
120
|
+
Given a file named "popup.rb" with:
|
121
|
+
"""ruby
|
122
|
+
class Popup
|
123
|
+
def self.alert(message, canvas)
|
124
|
+
canvas.background_color = "red"
|
125
|
+
# display message
|
126
|
+
end
|
127
|
+
end
|
128
|
+
"""
|
129
|
+
|
130
|
+
Then spec file with following content should pass:
|
131
|
+
"""ruby
|
132
|
+
require_relative 'canvas'
|
133
|
+
require_relative 'popup'
|
134
|
+
|
135
|
+
describe Popup do
|
136
|
+
fake(:canvas)
|
137
|
+
|
138
|
+
it "sets the background to red" do
|
139
|
+
Popup.alert("No such file!", canvas)
|
140
|
+
|
141
|
+
canvas.should have_received(:background_color=, "red")
|
142
|
+
end
|
143
|
+
end
|
144
|
+
"""
|
@@ -6,7 +6,6 @@ Given /^a spec file named "([^"]*)" with:$/ do |file_name, string|
|
|
6
6
|
Given a file named "#{file_name}" with:
|
7
7
|
"""ruby
|
8
8
|
require 'bogus/rspec'
|
9
|
-
require_relative 'foo'
|
10
9
|
|
11
10
|
#{string}
|
12
11
|
"""
|
@@ -26,7 +25,7 @@ Then /^all the specs should pass$/ do
|
|
26
25
|
end
|
27
26
|
|
28
27
|
When /^I run spec with the following content:$/ do |string|
|
29
|
-
file_name =
|
28
|
+
file_name = "foo_#{rand(1000000)}_spec.rb"
|
30
29
|
|
31
30
|
steps %Q{
|
32
31
|
Given a spec file named "#{file_name}" with:
|
data/features/support/env.rb
CHANGED
@@ -1,5 +1,24 @@
|
|
1
1
|
require 'aruba/cucumber'
|
2
|
+
require 'aruba/jruby'
|
2
3
|
|
3
4
|
Before('@known_bug') do
|
4
5
|
pending("This scenario fails because of a known bug")
|
5
6
|
end
|
7
|
+
|
8
|
+
Before do |scenario|
|
9
|
+
dir_name = "scenario-#{rand(1_000_000)}"
|
10
|
+
create_dir(dir_name)
|
11
|
+
cd(dir_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
Before do
|
15
|
+
@aruba_timeout_seconds = 60
|
16
|
+
end
|
17
|
+
|
18
|
+
if RUBY_PLATFORM == 'java' && ENV['TRAVIS']
|
19
|
+
Aruba.configure do |config|
|
20
|
+
config.before_cmd do
|
21
|
+
set_env('JAVA_OPTS', "#{ENV['JAVA_OPTS']} -d64")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -7,7 +7,7 @@ module Bogus
|
|
7
7
|
|
8
8
|
takes :klass, :instance_methods
|
9
9
|
|
10
|
-
def_delegators :
|
10
|
+
def_delegators :model_methods, :remove, :define
|
11
11
|
|
12
12
|
def all
|
13
13
|
return [] unless klass < ActiveRecord::Base
|
@@ -20,8 +20,8 @@ module Bogus
|
|
20
20
|
|
21
21
|
private
|
22
22
|
|
23
|
-
def
|
24
|
-
|
23
|
+
def model_methods
|
24
|
+
instance_methods.call(klass)
|
25
25
|
end
|
26
26
|
|
27
27
|
def all_attributes
|
@@ -29,7 +29,7 @@ module Bogus
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def missing_attributes
|
32
|
-
all_attributes -
|
32
|
+
all_attributes - model_methods.all
|
33
33
|
end
|
34
34
|
|
35
35
|
class Attribute < Struct.new(:name)
|