gimme 0.2.0 → 0.3.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.
Files changed (45) hide show
  1. data/Gemfile +3 -2
  2. data/Guardfile +1 -2
  3. data/LICENSE.txt +1 -1
  4. data/README.markdown +1 -1
  5. data/VERSION +1 -1
  6. data/features/basics.feature +66 -0
  7. data/features/matchers.feature +126 -0
  8. data/features/{argument_captors.feature → old/argument_captors.feature} +0 -0
  9. data/features/{gimme_next.feature → old/gimme_next.feature} +0 -0
  10. data/features/{stub_basic.feature → old/stub_basic.feature} +0 -0
  11. data/features/{stub_class_methods.feature → old/stub_class_methods.feature} +0 -1
  12. data/features/{stub_matchers.feature → old/stub_matchers.feature} +0 -0
  13. data/features/{stub_sensible_defaults.feature → old/stub_sensible_defaults.feature} +0 -0
  14. data/features/{unknown_methods.feature → old/unknown_methods.feature} +0 -0
  15. data/features/{verify_matcher_anything.feature → old/verify_matcher_anything.feature} +0 -0
  16. data/features/old/verify_no_args.feature +23 -0
  17. data/features/{verify_with_args.feature → old/verify_with_args.feature} +0 -0
  18. data/features/readme.md +3 -0
  19. data/features/step_definitions/doc_steps.rb +12 -0
  20. data/features/step_definitions/gimme_steps.rb +17 -0
  21. data/features/support/animals.rb +9 -0
  22. data/gimme.gemspec +35 -18
  23. data/lib/gimme.rb +8 -1
  24. data/lib/gimme/dsl.rb +19 -5
  25. data/lib/gimme/ensures_class_method_restoration.rb +18 -0
  26. data/lib/gimme/gives.rb +1 -2
  27. data/lib/gimme/gives_class_methods.rb +5 -29
  28. data/lib/gimme/invocation_store.rb +14 -0
  29. data/lib/gimme/invokes_satisfied_stubbing.rb +18 -10
  30. data/lib/gimme/method_store.rb +21 -0
  31. data/lib/gimme/reset.rb +10 -3
  32. data/lib/gimme/resolves_methods.rb +1 -1
  33. data/lib/gimme/spies_on_class_methods.rb +28 -0
  34. data/lib/gimme/store.rb +38 -0
  35. data/lib/gimme/stubbing_store.rb +17 -0
  36. data/lib/gimme/test_double.rb +13 -10
  37. data/lib/gimme/verifies.rb +10 -6
  38. data/lib/gimme/verifies_class_methods.rb +8 -0
  39. data/spec/gimme/shared_examples/shared_gives_examples.rb +28 -26
  40. data/spec/gimme/shared_examples/shared_verifies_examples.rb +91 -0
  41. data/spec/gimme/spies_on_class_method_spec.rb +58 -0
  42. data/spec/gimme/verifies_class_methods_spec.rb +46 -0
  43. data/spec/gimme/verifies_spec.rb +7 -94
  44. metadata +59 -42
  45. data/features/verify_no_args.feature +0 -18
data/Gemfile CHANGED
@@ -11,10 +11,11 @@ group :development, :test do
11
11
  gem "jeweler", "~> 1.5.2"
12
12
  gem "rspec"
13
13
  gem "rspec-given"
14
- gem "guard-rspec", :require => false
15
14
  gem "cucumber"
16
- gem "guard-cucumber", :require => false
17
15
  gem "simplecov", :require => false
16
+
17
+ gem "guard-cucumber", :require => false
18
+ gem "guard-rspec", :require => false
18
19
  if RUBY_PLATFORM =~ /darwin/i
19
20
  gem "growl"
20
21
  gem "rb-fsevent", :require => false
data/Guardfile CHANGED
@@ -3,11 +3,10 @@
3
3
 
4
4
  guard 'rspec', :cli => '--color', :version => 2 do
5
5
  watch(%r{^spec/.+_spec\.rb$})
6
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
7
  watch('spec/spec_helper.rb') { "spec" }
8
8
  end
9
9
 
10
-
11
10
  guard 'cucumber' do
12
11
  watch(%r{^features/.+\.feature$})
13
12
  watch(%r{^features/support/.+$}) { 'features' }
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Justin Searls
1
+ Copyright (c) 2012 Justin Searls
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -136,7 +136,7 @@ In cases like these, a captor can be used to "capture" the real argument value t
136
136
  #arrange
137
137
  searches_system = gimme(SearchesSystem)
138
138
  sut = QueryExecutor.new(searches_sytem)
139
- query_captor = Captor.new
139
+ query_captor = Gimme::Captor.new
140
140
 
141
141
  #act
142
142
  sut.submit_query_for_string("find dogs")
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.1
@@ -0,0 +1,66 @@
1
+ Feature: basic usage
2
+
3
+ Gimme is designed for easy & reliable isolated unit testing of Ruby classes.
4
+
5
+ This example illustrates:
6
+ <ul>
7
+ <li>How to create a test double for a known class</li>
8
+ <li>Injecting that double into the subject code we're specifying</li>
9
+ <li>Stubbing a method on a test double to return a particular result</li>
10
+ <li>Verify that a method on a test double was called with a particular argument</li>
11
+ </ul>
12
+
13
+ So say we've got a Chef who's job is to take the work product of his Apprentice
14
+ and simmer it on the Stove. Here's how we might use gimme to write an isolation test
15
+ of the Chef's job without actually calling through to a real Apprentice or a real Stove.
16
+
17
+ Scenario:
18
+ Given we have this existing code:
19
+ """
20
+ class Apprentice
21
+ def slice(thing)
22
+ 1000000.times.map do
23
+ Slice.new(thing)
24
+ end
25
+ end
26
+ end
27
+
28
+ class Stove
29
+ def simmer(stuff)
30
+ end
31
+ end
32
+
33
+ class Slice
34
+ def initialize(of)
35
+ end
36
+ end
37
+
38
+ class Chef
39
+ def initialize(slicer = Apprentice.new, stove = Stove.new)
40
+ @slicer = slicer
41
+ @stove = stove
42
+ end
43
+ end
44
+
45
+ """
46
+
47
+ When we want to write some tests to help us write this method:
48
+ """
49
+ class Chef
50
+ def cook
51
+ slices = @slicer.slice("tomato")
52
+ @stove.simmer(slices)
53
+ end
54
+ end
55
+ """
56
+
57
+ Then we can use gimme to isolate the unit under test:
58
+ """
59
+ slicer = gimme(Apprentice)
60
+ stove = gimme(Stove)
61
+ give(slicer).slice("tomato") { "some slices" }
62
+
63
+ Chef.new(slicer, stove).cook
64
+
65
+ verify(stove).simmer("some slices")
66
+ """
@@ -0,0 +1,126 @@
1
+ Feature: argument matchers
2
+
3
+ By default, gimme will only stub and verify methods that are called with the same arguments
4
+ in your spec and your production code. But gimme also includes a number of argument matchers
5
+ that allow more flexible specifications, particularly when you don't care about or can't
6
+ know the <em>exact</em> arguments passed to a method on a test double.
7
+
8
+ This example illustrates:
9
+ <ul>
10
+ <li>How to use an argument matcher when stubbing a method</li>
11
+ <li>Using argument matchers when verifying a method</li>
12
+ <li>Using argument captors, a special sort of matcher</li>
13
+ <li>Defining your own matcher</li>
14
+ </ul>
15
+
16
+ In this example, we have a Mail object with a contents attribute. A DeliversMessages object adds Mail to
17
+ Recipients' mailboxes and checks off each delivery on its Checklist.
18
+
19
+
20
+ Background:
21
+ Given we have this existing code:
22
+ """
23
+ class Mail
24
+ attr_reader :contents
25
+ def initialize(contents)
26
+ @contents = contents
27
+ end
28
+ end
29
+
30
+ class Recipient
31
+ def add_to_mailbox(thing)
32
+ end
33
+ end
34
+
35
+ class Checklist
36
+ def check_off(message_summary, recipient, timestamp)
37
+ end
38
+ end
39
+
40
+ class DeliversMessages
41
+ def initialize(checklist = Checklist.new)
42
+ @checklist = checklist
43
+ end
44
+ end
45
+ """
46
+ When we want to write some tests to help us write this method:
47
+ """
48
+ class DeliversMessages
49
+ def deliver(message, recipient = Recipient.new)
50
+ mail = Mail.new(message)
51
+ recipient.add_to_mailbox(mail)
52
+ @checklist.check_off(message[0..4], recipient, Time.now)
53
+ end
54
+ end
55
+ """
56
+
57
+ Scenario: using the is_a matcher to specify a type
58
+ Then we can use gimme to isolate the unit under test:
59
+ """
60
+ checklist = gimme(Checklist)
61
+ recipient = gimme(Recipient)
62
+
63
+ DeliversMessages.new(checklist).deliver("WHY HELLO GOOD SIR", recipient)
64
+
65
+ #without access (or interest in) the mail object, we can just check it was of type Mail
66
+ verify(recipient).add_to_mailbox(is_a(Mail))
67
+
68
+ # ^-- we could have also used any(Mail) to allow the argument to have been nil, as well.
69
+ """
70
+
71
+ Scenario: using the anything matcher to allow for any value
72
+
73
+ Then we can use gimme to isolate the unit under test:
74
+ """
75
+ checklist = gimme(Checklist)
76
+ recipient = gimme(Recipient)
77
+
78
+ DeliversMessages.new(checklist).deliver("WHY HELLO GOOD SIR", recipient)
79
+
80
+ #here we check the second param exactly, but allow the third to be anything
81
+ verify(checklist).check_off(any(String), recipient, anything)
82
+ """
83
+
84
+ Scenario: using an argument captor to grab what was passed
85
+ Then we can use gimme to isolate the unit under test:
86
+ """
87
+ checklist = gimme(Checklist)
88
+ recipient = gimme(Recipient)
89
+
90
+ DeliversMessages.new(checklist).deliver("WHY HELLO GOOD SIR", recipient)
91
+
92
+ mail_captor = Gimme::Captor.new
93
+ verify(recipient).add_to_mailbox(capture(mail_captor))
94
+ mail_captor.value.contents.should == "WHY HELLO GOOD SIR"
95
+ """
96
+
97
+ Scenario: writing a custom starts_with matcher
98
+ Then we can use gimme to isolate the unit under test:
99
+ """
100
+ checklist = gimme(Checklist)
101
+ recipient = gimme(Recipient)
102
+
103
+ DeliversMessages.new(checklist).deliver("WHY HELLO GOOD SIR", recipient)
104
+
105
+
106
+ class StartsWith
107
+ def initialize(expected)
108
+ @expected = expected
109
+ end
110
+
111
+ def matches?(actual)
112
+ actual.start_with?(@expected)
113
+ end
114
+ end
115
+
116
+ verify(checklist).check_off(StartsWith.new("WHY"), anything, anything)
117
+
118
+ # or, of course, you could add a more natural method for your matcher
119
+
120
+ def starts_with(s)
121
+ StartsWith.new(s)
122
+ end
123
+
124
+ verify(checklist).check_off(starts_with("WHY"), anything, anything)
125
+
126
+ """
@@ -1,4 +1,3 @@
1
- @wip
2
1
  Feature: stubbing class methods
3
2
 
4
3
  In order to spec code that depends on Rails or other APIs that make
@@ -0,0 +1,23 @@
1
+ Feature: verification of no-arg methods
2
+
3
+ As a test author
4
+ I want to verify my test double's no-arg method was invoked
5
+ So that I can specify its behavior
6
+
7
+ Scenario:
8
+ Given a new test double
9
+ But I do not invoke yawn
10
+ Then verifying yawn raises a Gimme::Errors::VerificationFailedError
11
+ But I can verify yawn has been invoked 0 times
12
+
13
+ When I invoke yawn
14
+ Then I can verify yawn has been invoked
15
+ And I can verify yawn has been invoked 1 time
16
+
17
+ When I invoke yawn
18
+ Then I can verify yawn has been invoked 2 times
19
+
20
+ Scenario: class methods
21
+ Given the ClassyPossum class
22
+ When I spy on ClassyPossum.yawn
23
+ Then it can verify no-arg methods too.
@@ -0,0 +1,3 @@
1
+ # gimme
2
+
3
+ Gimme is a test double library designed to help you write isolated unit specs for your Ruby code.
@@ -0,0 +1,12 @@
1
+
2
+ Given /^we have this existing code:$/ do |string|
3
+ eval(string)
4
+ end
5
+
6
+ When /^we want to write some tests to help us write this method:$/ do |string|
7
+ eval(string)
8
+ end
9
+
10
+ Then /^we can use gimme to isolate the unit under test:$/ do |string|
11
+ eval(string)
12
+ end
@@ -75,6 +75,23 @@ Then /^I can verify! #{METHOD_PATTERN} has been invoked (\d+) times?$/ do |metho
75
75
  sendish(verify!(@double,times.to_i),method,args)
76
76
  end
77
77
 
78
+ When /^I spy on ([^.]*)\.(.*)$/ do |cls, method|
79
+ spy_on(eval(cls), method.to_sym)
80
+ end
81
+
82
+ Then /^it can verify no\-arg methods too\.$/ do
83
+ step "I do not invoke yawn"
84
+ step "verifying yawn raises a Gimme::Errors::VerificationFailedError"
85
+ step "I can verify yawn has been invoked 0 times"
86
+
87
+ step "I invoke yawn"
88
+ step "I can verify yawn has been invoked"
89
+ step "I can verify yawn has been invoked 1 time"
90
+
91
+ step "I invoke yawn"
92
+ step "I can verify yawn has been invoked 2 times"
93
+ end
94
+
78
95
  #Captors
79
96
 
80
97
  Given /^a new argument captor$/ do
@@ -16,6 +16,15 @@ class Possum
16
16
 
17
17
  def self.crawl_to(location)
18
18
  end
19
+
20
+ def yawn
21
+
22
+ end
23
+ end
24
+
25
+ class ClassyPossum
26
+ def self.yawn
27
+ end
19
28
  end
20
29
 
21
30
  class Dog < Animal
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{gimme}
8
- s.version = "0.2.0"
8
+ s.version = "0.3.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = [%q{Justin Searls}]
12
- s.date = %q{2012-02-27}
12
+ s.date = %q{2012-03-03}
13
13
  s.description = %q{gimme attempts to bring to Ruby a test double workflow akin to Mockito in Java. Major distinctions include preserving arrange-act-assert in tests, fast feedback for methods the double's real counterpart may not know how to respond to, no string/symbolic representations of methods, argument captors, and strong opinions (weakly held). }
14
14
  s.email = %q{searls@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -28,34 +28,45 @@ Gem::Specification.new do |s|
28
28
  "README.rdoc",
29
29
  "Rakefile",
30
30
  "VERSION",
31
- "features/argument_captors.feature",
32
- "features/gimme_next.feature",
31
+ "features/basics.feature",
32
+ "features/matchers.feature",
33
+ "features/old/argument_captors.feature",
34
+ "features/old/gimme_next.feature",
35
+ "features/old/stub_basic.feature",
36
+ "features/old/stub_class_methods.feature",
37
+ "features/old/stub_matchers.feature",
38
+ "features/old/stub_sensible_defaults.feature",
39
+ "features/old/unknown_methods.feature",
40
+ "features/old/verify_matcher_anything.feature",
41
+ "features/old/verify_no_args.feature",
42
+ "features/old/verify_with_args.feature",
43
+ "features/readme.md",
44
+ "features/step_definitions/doc_steps.rb",
33
45
  "features/step_definitions/gimme_steps.rb",
34
- "features/stub_basic.feature",
35
- "features/stub_class_methods.feature",
36
- "features/stub_matchers.feature",
37
- "features/stub_sensible_defaults.feature",
38
46
  "features/support/animals.rb",
39
47
  "features/support/env.rb",
40
- "features/unknown_methods.feature",
41
- "features/verify_matcher_anything.feature",
42
- "features/verify_no_args.feature",
43
- "features/verify_with_args.feature",
44
48
  "gimme.gemspec",
45
49
  "lib/gimme-double.rb",
46
50
  "lib/gimme.rb",
47
51
  "lib/gimme/captor.rb",
48
52
  "lib/gimme/dsl.rb",
53
+ "lib/gimme/ensures_class_method_restoration.rb",
49
54
  "lib/gimme/errors.rb",
50
55
  "lib/gimme/gives.rb",
51
56
  "lib/gimme/gives_class_methods.rb",
57
+ "lib/gimme/invocation_store.rb",
52
58
  "lib/gimme/invokes_satisfied_stubbing.rb",
53
59
  "lib/gimme/matchers.rb",
60
+ "lib/gimme/method_store.rb",
54
61
  "lib/gimme/reset.rb",
55
62
  "lib/gimme/resolves_methods.rb",
56
63
  "lib/gimme/rspec_adapter.rb",
64
+ "lib/gimme/spies_on_class_methods.rb",
65
+ "lib/gimme/store.rb",
66
+ "lib/gimme/stubbing_store.rb",
57
67
  "lib/gimme/test_double.rb",
58
68
  "lib/gimme/verifies.rb",
69
+ "lib/gimme/verifies_class_methods.rb",
59
70
  "spec/gimme/captor_spec.rb",
60
71
  "spec/gimme/errors_spec.rb",
61
72
  "spec/gimme/gives_class_methods_spec.rb",
@@ -64,7 +75,10 @@ Gem::Specification.new do |s|
64
75
  "spec/gimme/resolves_methods_spec.rb",
65
76
  "spec/gimme/rspec_adapter_spec.rb",
66
77
  "spec/gimme/shared_examples/shared_gives_examples.rb",
78
+ "spec/gimme/shared_examples/shared_verifies_examples.rb",
79
+ "spec/gimme/spies_on_class_method_spec.rb",
67
80
  "spec/gimme/test_double_spec.rb",
81
+ "spec/gimme/verifies_class_methods_spec.rb",
68
82
  "spec/gimme/verifies_spec.rb",
69
83
  "spec/spec_helper.rb"
70
84
  ]
@@ -82,7 +96,10 @@ Gem::Specification.new do |s|
82
96
  "spec/gimme/resolves_methods_spec.rb",
83
97
  "spec/gimme/rspec_adapter_spec.rb",
84
98
  "spec/gimme/shared_examples/shared_gives_examples.rb",
99
+ "spec/gimme/shared_examples/shared_verifies_examples.rb",
100
+ "spec/gimme/spies_on_class_method_spec.rb",
85
101
  "spec/gimme/test_double_spec.rb",
102
+ "spec/gimme/verifies_class_methods_spec.rb",
86
103
  "spec/gimme/verifies_spec.rb",
87
104
  "spec/spec_helper.rb"
88
105
  ]
@@ -96,10 +113,10 @@ Gem::Specification.new do |s|
96
113
  s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
97
114
  s.add_development_dependency(%q<rspec>, [">= 0"])
98
115
  s.add_development_dependency(%q<rspec-given>, [">= 0"])
99
- s.add_development_dependency(%q<guard-rspec>, [">= 0"])
100
116
  s.add_development_dependency(%q<cucumber>, [">= 0"])
101
- s.add_development_dependency(%q<guard-cucumber>, [">= 0"])
102
117
  s.add_development_dependency(%q<simplecov>, [">= 0"])
118
+ s.add_development_dependency(%q<guard-cucumber>, [">= 0"])
119
+ s.add_development_dependency(%q<guard-rspec>, [">= 0"])
103
120
  s.add_development_dependency(%q<growl>, [">= 0"])
104
121
  s.add_development_dependency(%q<rb-fsevent>, [">= 0"])
105
122
  s.add_development_dependency(%q<rspec>, [">= 1.3.1"])
@@ -110,10 +127,10 @@ Gem::Specification.new do |s|
110
127
  s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
111
128
  s.add_dependency(%q<rspec>, [">= 0"])
112
129
  s.add_dependency(%q<rspec-given>, [">= 0"])
113
- s.add_dependency(%q<guard-rspec>, [">= 0"])
114
130
  s.add_dependency(%q<cucumber>, [">= 0"])
115
- s.add_dependency(%q<guard-cucumber>, [">= 0"])
116
131
  s.add_dependency(%q<simplecov>, [">= 0"])
132
+ s.add_dependency(%q<guard-cucumber>, [">= 0"])
133
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
117
134
  s.add_dependency(%q<growl>, [">= 0"])
118
135
  s.add_dependency(%q<rb-fsevent>, [">= 0"])
119
136
  s.add_dependency(%q<rspec>, [">= 1.3.1"])
@@ -125,10 +142,10 @@ Gem::Specification.new do |s|
125
142
  s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
126
143
  s.add_dependency(%q<rspec>, [">= 0"])
127
144
  s.add_dependency(%q<rspec-given>, [">= 0"])
128
- s.add_dependency(%q<guard-rspec>, [">= 0"])
129
145
  s.add_dependency(%q<cucumber>, [">= 0"])
130
- s.add_dependency(%q<guard-cucumber>, [">= 0"])
131
146
  s.add_dependency(%q<simplecov>, [">= 0"])
147
+ s.add_dependency(%q<guard-cucumber>, [">= 0"])
148
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
132
149
  s.add_dependency(%q<growl>, [">= 0"])
133
150
  s.add_dependency(%q<rb-fsevent>, [">= 0"])
134
151
  s.add_dependency(%q<rspec>, [">= 1.3.1"])