gimme 0.2.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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"])