bogus 0.0.1
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/.gitignore +7 -0
- data/.pelusa.yml +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +75 -0
- data/Guardfile +15 -0
- data/README.md +272 -0
- data/Rakefile +1 -0
- data/bogus.gemspec +34 -0
- data/features/configuration_options.feature +43 -0
- data/features/contract_tests_mocks.feature +100 -0
- data/features/contract_tests_spies.feature +72 -0
- data/features/contract_tests_stubs.feature +101 -0
- data/features/fake_objects.feature +94 -0
- data/features/return_value_contracts.feature +90 -0
- data/features/safe_mocking.feature +59 -0
- data/features/safe_stubbing.feature +62 -0
- data/features/spies.feature +78 -0
- data/features/step_definitions/rspec_steps.rb +68 -0
- data/features/support/env.rb +1 -0
- data/lib/bogus.rb +35 -0
- data/lib/bogus/adds_recording.rb +11 -0
- data/lib/bogus/configuration.rb +9 -0
- data/lib/bogus/contract_not_fulfilled.rb +24 -0
- data/lib/bogus/converts_name_to_class.rb +31 -0
- data/lib/bogus/copies_classes.rb +44 -0
- data/lib/bogus/creates_fakes.rb +32 -0
- data/lib/bogus/double.rb +10 -0
- data/lib/bogus/fake.rb +33 -0
- data/lib/bogus/fake_registry.rb +13 -0
- data/lib/bogus/injector.rb +64 -0
- data/lib/bogus/interaction.rb +24 -0
- data/lib/bogus/interaction_presenter.rb +29 -0
- data/lib/bogus/interactions_repository.rb +19 -0
- data/lib/bogus/invocation_matcher.rb +27 -0
- data/lib/bogus/method_stringifier.rb +31 -0
- data/lib/bogus/overwrites_classes.rb +9 -0
- data/lib/bogus/proxy_class.rb +22 -0
- data/lib/bogus/public_methods.rb +46 -0
- data/lib/bogus/record_interactions.rb +17 -0
- data/lib/bogus/recording_proxy.rb +18 -0
- data/lib/bogus/records_double_interactions.rb +11 -0
- data/lib/bogus/registers_created_fakes.rb +11 -0
- data/lib/bogus/rr_proxy.rb +5 -0
- data/lib/bogus/rspec.rb +4 -0
- data/lib/bogus/rspec_extensions.rb +32 -0
- data/lib/bogus/takes.rb +8 -0
- data/lib/bogus/verifies_contracts.rb +12 -0
- data/lib/bogus/verifies_stub_definition.rb +37 -0
- data/lib/bogus/version.rb +3 -0
- data/pelusa.sh +3 -0
- data/rbs.sh +3 -0
- data/spec/bogus/adds_recording_spec.rb +33 -0
- data/spec/bogus/configuration_spec.rb +17 -0
- data/spec/bogus/converts_name_to_class_spec.rb +40 -0
- data/spec/bogus/copies_classes_spec.rb +175 -0
- data/spec/bogus/creates_fakes_spec.rb +59 -0
- data/spec/bogus/double_spec.rb +31 -0
- data/spec/bogus/fake_registry_spec.rb +24 -0
- data/spec/bogus/interaction_spec.rb +68 -0
- data/spec/bogus/interactions_repository_spec.rb +50 -0
- data/spec/bogus/invocation_matcher_spec.rb +26 -0
- data/spec/bogus/mocking_dsl_spec.rb +76 -0
- data/spec/bogus/overwrites_classes_spec.rb +26 -0
- data/spec/bogus/proxy_class_spec.rb +95 -0
- data/spec/bogus/record_interactions_spec.rb +27 -0
- data/spec/bogus/records_double_interactions_spec.rb +25 -0
- data/spec/bogus/registers_created_fakes_spec.rb +25 -0
- data/spec/bogus/verifies_contracts_spec.rb +42 -0
- data/spec/bogus/verifies_stub_definition_spec.rb +71 -0
- data/spec/spec_helper.rb +14 -0
- metadata +299 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
Feature: Contract tests with mocks
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given a file named "foo.rb" with:
|
5
|
+
"""ruby
|
6
|
+
class Library
|
7
|
+
def initialize
|
8
|
+
@books = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def has_book?(book)
|
12
|
+
@books.include?(book)
|
13
|
+
end
|
14
|
+
|
15
|
+
def checkout(book)
|
16
|
+
@books.delete(book)
|
17
|
+
end
|
18
|
+
|
19
|
+
def return(book)
|
20
|
+
@books << book
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Student
|
25
|
+
def read(book, library = Library.new)
|
26
|
+
if library.has_book?(book)
|
27
|
+
library.checkout(book)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
"""
|
32
|
+
And a spec file named "student_spec.rb" with:
|
33
|
+
"""ruby
|
34
|
+
describe Student do
|
35
|
+
fake(:library)
|
36
|
+
|
37
|
+
it "checks out the book from library if it is available" do
|
38
|
+
student = Student.new
|
39
|
+
mock(library).has_book?("Moby Dick") { true }
|
40
|
+
mock(library).checkout("Moby Dick") { "Moby Dick" }
|
41
|
+
|
42
|
+
student.read("Moby Dick", library)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "does not check out the book from library if not available" do
|
46
|
+
student = Student.new
|
47
|
+
mock(library).has_book?("Moby Dick") { false }
|
48
|
+
dont_allow(library).checkout("Moby Dick")
|
49
|
+
|
50
|
+
student.read("Moby Dick", library)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
"""
|
54
|
+
|
55
|
+
Scenario: Fails when mocked methods are not called on real object
|
56
|
+
Then spec file with following content should fail:
|
57
|
+
"""ruby
|
58
|
+
describe Library do
|
59
|
+
verify_contract(:library)
|
60
|
+
|
61
|
+
let(:library) { Library.new }
|
62
|
+
|
63
|
+
it "marks books as unavailable after they are checked out" do
|
64
|
+
library.return("Moby Dick")
|
65
|
+
|
66
|
+
library.checkout("Moby Dick")
|
67
|
+
|
68
|
+
library.has_book?("Moby Dick").should be_false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
"""
|
72
|
+
|
73
|
+
Scenario: Verifies that mocked methods are called
|
74
|
+
Then spec file with following content should pass:
|
75
|
+
"""ruby
|
76
|
+
describe Library do
|
77
|
+
verify_contract(:library)
|
78
|
+
|
79
|
+
let(:library) { Library.new }
|
80
|
+
|
81
|
+
it "allows checking out books that are in the inventory" do
|
82
|
+
library.return("Moby Dick")
|
83
|
+
|
84
|
+
library.has_book?("Moby Dick").should be_true
|
85
|
+
end
|
86
|
+
|
87
|
+
it "does not allow checking out unavailable books" do
|
88
|
+
library.has_book?("Moby Dick").should be_false
|
89
|
+
end
|
90
|
+
|
91
|
+
it "marks books as unavailable after they are checked out" do
|
92
|
+
library.return("Moby Dick")
|
93
|
+
|
94
|
+
library.checkout("Moby Dick")
|
95
|
+
|
96
|
+
library.has_book?("Moby Dick").should be_false
|
97
|
+
end
|
98
|
+
end
|
99
|
+
"""
|
100
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
Feature: Contract tests with spies
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given a file named "foo.rb" with:
|
5
|
+
"""ruby
|
6
|
+
class Library
|
7
|
+
def checkout(book)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Student
|
12
|
+
def read(book, library = Libarary.new)
|
13
|
+
library.checkout(book)
|
14
|
+
# ...
|
15
|
+
end
|
16
|
+
end
|
17
|
+
"""
|
18
|
+
And a spec file named "student_spec.rb" with:
|
19
|
+
"""ruby
|
20
|
+
describe Student do
|
21
|
+
fake(:library)
|
22
|
+
|
23
|
+
it "reads books from library" do
|
24
|
+
student = Student.new
|
25
|
+
|
26
|
+
student.read("Moby Dick", library)
|
27
|
+
|
28
|
+
library.should have_received.checkout("Moby Dick")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
"""
|
32
|
+
|
33
|
+
Scenario: Stubbing methods that exist on real object
|
34
|
+
Then spec file with following content should pass:
|
35
|
+
"""ruby
|
36
|
+
describe Library do
|
37
|
+
verify_contract(:library)
|
38
|
+
|
39
|
+
it "checks out books" do
|
40
|
+
library = Library.new
|
41
|
+
|
42
|
+
library.checkout("Moby Dick")
|
43
|
+
|
44
|
+
# ...
|
45
|
+
end
|
46
|
+
end
|
47
|
+
"""
|
48
|
+
|
49
|
+
Scenario: Verifing that stubbed methods are tested
|
50
|
+
Then spec file with following content should fail:
|
51
|
+
"""ruby
|
52
|
+
describe Library do
|
53
|
+
verify_contract(:library)
|
54
|
+
|
55
|
+
end
|
56
|
+
"""
|
57
|
+
|
58
|
+
Scenario: Verifying that methods are tested with right arguments
|
59
|
+
Then spec file with following content should fail:
|
60
|
+
"""ruby
|
61
|
+
describe Library do
|
62
|
+
verify_contract(:library)
|
63
|
+
|
64
|
+
it "checks out books" do
|
65
|
+
library = Library.new
|
66
|
+
|
67
|
+
library.checkout("Moby Dick 2: The ulitmate")
|
68
|
+
|
69
|
+
# ...
|
70
|
+
end
|
71
|
+
end
|
72
|
+
"""
|
@@ -0,0 +1,101 @@
|
|
1
|
+
Feature: Contract tests with stubs
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given a file named "foo.rb" with:
|
5
|
+
"""ruby
|
6
|
+
class Library
|
7
|
+
def initialize
|
8
|
+
@books = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def has_book?(book)
|
12
|
+
@books.include?(book)
|
13
|
+
end
|
14
|
+
|
15
|
+
def checkout(book)
|
16
|
+
@books.delete(book)
|
17
|
+
end
|
18
|
+
|
19
|
+
def return(book)
|
20
|
+
@books << book
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Student
|
25
|
+
def read(book, library = Library.new)
|
26
|
+
if library.has_book?(book)
|
27
|
+
library.checkout(book)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
"""
|
32
|
+
And a spec file named "student_spec.rb" with:
|
33
|
+
"""ruby
|
34
|
+
describe Student do
|
35
|
+
fake(:library)
|
36
|
+
|
37
|
+
it "checks out the book from library if it is available" do
|
38
|
+
student = Student.new
|
39
|
+
stub(library).has_book?("Moby Dick") { true }
|
40
|
+
|
41
|
+
student.read("Moby Dick", library)
|
42
|
+
|
43
|
+
library.should have_received.checkout("Moby Dick")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "does not check out the book from library if not available" do
|
47
|
+
student = Student.new
|
48
|
+
stub(library).has_book?("Moby Dick") { false }
|
49
|
+
|
50
|
+
student.read("Moby Dick", library)
|
51
|
+
|
52
|
+
library.should_not have_received.checkout("Moby Dick")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
"""
|
56
|
+
|
57
|
+
Scenario: Fails when stubbed methods are not called on real object
|
58
|
+
Then spec file with following content should fail:
|
59
|
+
"""ruby
|
60
|
+
describe Library do
|
61
|
+
verify_contract(:library)
|
62
|
+
|
63
|
+
let(:library) { Library.new }
|
64
|
+
|
65
|
+
it "marks books as unavailable after they are checked out" do
|
66
|
+
library.return("Moby Dick")
|
67
|
+
|
68
|
+
library.checkout("Moby Dick")
|
69
|
+
|
70
|
+
library.has_book?("Moby Dick").should be_false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
"""
|
74
|
+
|
75
|
+
Scenario: Verifies that stubbed methods are called
|
76
|
+
Then spec file with following content should pass:
|
77
|
+
"""ruby
|
78
|
+
describe Library do
|
79
|
+
verify_contract(:library)
|
80
|
+
|
81
|
+
let(:library) { Library.new }
|
82
|
+
|
83
|
+
it "allows checking out books that are in the inventory" do
|
84
|
+
library.return("Moby Dick")
|
85
|
+
|
86
|
+
library.has_book?("Moby Dick").should be_true
|
87
|
+
end
|
88
|
+
|
89
|
+
it "does not allow checking out unavailable books" do
|
90
|
+
library.has_book?("Moby Dick").should be_false
|
91
|
+
end
|
92
|
+
|
93
|
+
it "marks books as unavailable after they are checked out" do
|
94
|
+
library.return("Moby Dick")
|
95
|
+
|
96
|
+
library.checkout("Moby Dick")
|
97
|
+
|
98
|
+
library.has_book?("Moby Dick").should be_false
|
99
|
+
end
|
100
|
+
end
|
101
|
+
"""
|
@@ -0,0 +1,94 @@
|
|
1
|
+
Feature: Faking existing classes
|
2
|
+
|
3
|
+
Bogus makes it easy to create fakes, which behave like a null-object and
|
4
|
+
have the same interface as the object being faked.
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given a file named "foo.rb" with:
|
8
|
+
"""ruby
|
9
|
+
class Library
|
10
|
+
def checkout(book)
|
11
|
+
end
|
12
|
+
|
13
|
+
def return_book(book)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.look_up(book)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Student
|
21
|
+
def self.learn(library = Library.new)
|
22
|
+
library.checkout("hello world")
|
23
|
+
true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
"""
|
27
|
+
|
28
|
+
Scenario: Calling methods that exist on real object
|
29
|
+
Then spec file with following content should pass:
|
30
|
+
"""ruby
|
31
|
+
describe Student do
|
32
|
+
fake(:library)
|
33
|
+
|
34
|
+
it "does something" do
|
35
|
+
Student.learn(library).should be_true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
"""
|
39
|
+
|
40
|
+
Scenario: Fakes have null-object semantics
|
41
|
+
Then spec file with following content should pass:
|
42
|
+
"""ruby
|
43
|
+
describe "library fake" do
|
44
|
+
fake(:library)
|
45
|
+
|
46
|
+
it "returns self from all methods" do
|
47
|
+
library.checkout("hello").should == library
|
48
|
+
end
|
49
|
+
|
50
|
+
it "makes method chaining possible" do
|
51
|
+
library.checkout("hello").return_book("world").should == library
|
52
|
+
end
|
53
|
+
end
|
54
|
+
"""
|
55
|
+
|
56
|
+
Scenario: Taking the guesswork out of finding a class to copy
|
57
|
+
Then spec file with following content should pass:
|
58
|
+
"""ruby
|
59
|
+
class PublicLibrary
|
60
|
+
def checkout(book)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "logger fake" do
|
65
|
+
fake(:library) { PublicLibrary }
|
66
|
+
|
67
|
+
it "uses the class provided in block instead of the guessed one" do
|
68
|
+
library.class.name.should == "PublicLibrary"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
"""
|
72
|
+
|
73
|
+
Scenario: Fakes which are classes
|
74
|
+
Then spec file with following content should pass:
|
75
|
+
"""ruby
|
76
|
+
describe "library class fake" do
|
77
|
+
fake(:library, as: :class)
|
78
|
+
|
79
|
+
it "is a class" do
|
80
|
+
library.should be_a(Class)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "has the same name as original class" do
|
84
|
+
library.name.should == Library.name
|
85
|
+
end
|
86
|
+
|
87
|
+
it "has same methods as original class" do
|
88
|
+
library.look_up('something')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
"""
|
92
|
+
|
93
|
+
Scenario: Fakes which are objects
|
94
|
+
Given pending
|
@@ -0,0 +1,90 @@
|
|
1
|
+
Feature: Return value contracts
|
2
|
+
|
3
|
+
Background:
|
4
|
+
Given a file named "foo.rb" with:
|
5
|
+
"""ruby
|
6
|
+
class SessionController
|
7
|
+
def initialize(authentication_service)
|
8
|
+
@authentication_service = authentication_service
|
9
|
+
end
|
10
|
+
|
11
|
+
def create(params)
|
12
|
+
@authentication_service.authenticate(params[:login], params[:password])
|
13
|
+
:render_welcome
|
14
|
+
rescue
|
15
|
+
:render_error
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class WrongPassword < StandardError
|
20
|
+
end
|
21
|
+
|
22
|
+
class AuthenticationService
|
23
|
+
def initialize(user_db)
|
24
|
+
@user_db = user_db
|
25
|
+
end
|
26
|
+
|
27
|
+
def authenticate(login, password)
|
28
|
+
unless @user_db[login] == Digest::SHA1.hexdigest(password)
|
29
|
+
raise WrongPassword
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
"""
|
34
|
+
And a spec file named "session_controller_spec.rb" with:
|
35
|
+
"""ruby
|
36
|
+
describe SessionController do
|
37
|
+
fake(:authentication_service)
|
38
|
+
let(:controller) { SessionController.new(authentication_service) }
|
39
|
+
|
40
|
+
it "logs in the user with valid data" do
|
41
|
+
stub(authentication_service).authenticate('foo', 'bar')
|
42
|
+
|
43
|
+
controller.create(login: 'foo', password: 'bar').should == :render_welcome
|
44
|
+
end
|
45
|
+
|
46
|
+
it "fails with invalid data" do
|
47
|
+
stub(authentication_service).authenticate('baz', 'bar') { raise WrongPassword }
|
48
|
+
|
49
|
+
controller.create(login: 'baz', password: 'bar').should == :render_error
|
50
|
+
end
|
51
|
+
end
|
52
|
+
"""
|
53
|
+
|
54
|
+
Scenario: Fails when returned values differ
|
55
|
+
Then spec file with following content should fail:
|
56
|
+
"""ruby
|
57
|
+
describe AuthenticationService do
|
58
|
+
verify_contract(:authentication_service)
|
59
|
+
|
60
|
+
it "logs in the user" do
|
61
|
+
service = AuthenticationService.new('foo' => Digest::SHA1.hexdigest('bar'))
|
62
|
+
expect {
|
63
|
+
service.authenticate('foo', 'bar')
|
64
|
+
}.not_to raise_error
|
65
|
+
end
|
66
|
+
end
|
67
|
+
"""
|
68
|
+
|
69
|
+
Scenario: Passes when interfaces match
|
70
|
+
Then spec file with following content should pass:
|
71
|
+
"""ruby
|
72
|
+
describe AuthenticationService do
|
73
|
+
verify_contract(:authentication_service)
|
74
|
+
|
75
|
+
it "logs in the user" do
|
76
|
+
service = AuthenticationService.new('foo' => Digest::SHA1.hexdigest('bar'))
|
77
|
+
expect {
|
78
|
+
service.authenticate('foo', 'bar')
|
79
|
+
}.not_to raise_error
|
80
|
+
end
|
81
|
+
|
82
|
+
it "raises WrongPassword with incorrect credentials" do
|
83
|
+
service = AuthenticationService.new('foo' => Digest::SHA1.hexdigest('bar'))
|
84
|
+
expect {
|
85
|
+
service.authenticate('baz', 'bar')
|
86
|
+
}.to raise_error(WrongPassword)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
"""
|
90
|
+
|