rspec-varys 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c9b5d6746ad0ced69ace33d7f785783a1a9289c3
4
- data.tar.gz: e5579d289843714febeddd99b882d95f79c94779
3
+ metadata.gz: cbc742320b2d49ca1b0ccfb05d60c189212820f4
4
+ data.tar.gz: d56e9a8c273902aedab09c984a1e7c17249dad03
5
5
  SHA512:
6
- metadata.gz: 4b25c426e5f447bb33d3d2216c0b593d0d1be37ab1be19223217b706a4a54a1d8dd796e779fea428c487a34443086e2da95178ae78e1d6613ea1dfb60ab99ddc
7
- data.tar.gz: e485f28b72288b5ecf2212e1c3f7bcfd115a32918838f6a8a1e9ac93ed6ae4046a3cd0c7a07b9de7ed15cfc9b22e2d53b96f9b9e99645a4fbb9a28e727b58c3d
6
+ metadata.gz: 1494635acd2c1106fe2309477866dcb3cb9782d4937144e1feaf0bf681cbb3197c051c6e56eb0fdf02cad15921a1afedb27c0b27db0cc5c2ce90c68718a0e81b
7
+ data.tar.gz: 79b1b8d13c8b9bf5fbd23fa14d48cfc9ebe4972f69fea4ec4ef184524ef7a6f4e4a05b411c748d5e86ae4320778d0d89927ea679f202adc9a42e5c3343b3d22c
data/Gemfile CHANGED
@@ -1,5 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
-
5
- gem 'pry-rescue'
data/bin/genspecs ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+
@@ -6,6 +6,7 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
6
6
  $:.unshift File.expand_path('../../lib', File.dirname(__FILE__))
7
7
 
8
8
  require "rspec/varys"
9
+ require "rspec/varys/rspec_generator"
9
10
 
10
11
  RSpec.configure do |config|
11
12
 
@@ -17,6 +18,7 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
17
18
 
18
19
  config.after(:suite) do
19
20
  RSpec::Varys.print_report
21
+ RSpec::Varys::RSpecGenerator.run
20
22
  end
21
23
  end
22
24
  """
@@ -54,24 +56,29 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
54
56
 
55
57
  When I run `rspec top_level_spec.rb`
56
58
  Then it should pass with:
57
- """
59
+ """ruby
58
60
  Specs have been generated based on mocks you aren't currently testing.
59
61
  """
60
- And the file "generated_specs/person_spec.rb" should contain:
62
+ And the file "varys.yaml" should contain:
63
+ """yaml
64
+ ---
65
+ :untested_stubs:
66
+ - :class_name: Person
67
+ :method: full_name
68
+ :returns: Dick Jones
61
69
  """
62
- describe Person do
63
70
 
64
- describe "#full_name" do
65
-
66
- it "returns the correct value" do
67
- pending
68
- confirm(subject).can receive(:full_name).and_return("Dick Jones")
69
- expect(subject.full_name).to eq("Dick Jones")
70
- end
71
+ And the file "generated_specs.rb" should contain:
72
+ """ruby
73
+ describe Person, "#full_name" do
71
74
 
75
+ it "returns something" do
76
+ expect(subject.full_name).to return("Dick Jones")
72
77
  end
73
78
 
74
79
  end
80
+
81
+
75
82
  """
76
83
 
77
84
 
@@ -108,36 +115,44 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
108
115
 
109
116
  When I run `rspec top_level_spec.rb`
110
117
  Then it should pass with:
111
- """
118
+ """ruby
112
119
  Specs have been generated based on mocks you aren't currently testing.
113
120
  """
114
- And the file "generated_specs/person_spec.rb" should contain:
121
+ And the file "varys.yaml" should contain:
122
+ """yaml
123
+ ---
124
+ :untested_stubs:
125
+ - :class_name: Person
126
+ :method: title
127
+ :returns: Vice President
128
+ - :class_name: Person
129
+ :method: full_name
130
+ :returns: Dick Jones
115
131
  """
116
- describe Person do
117
-
118
- describe "#title" do
119
132
 
120
- it "returns the correct value" do
121
- pending
122
- confirm(subject).can receive(:title).and_return("Vice President")
123
- expect(subject.title).to eq("Vice President")
124
- end
133
+ And the file "generated_specs.rb" should contain:
134
+ """ruby
135
+ describe Person, "#title" do
125
136
 
137
+ it "returns something" do
138
+ expect(subject.title).to return("Vice President")
126
139
  end
127
140
 
128
- describe "#full_name" do
141
+ end
129
142
 
130
- it "returns the correct value" do
131
- pending
132
- confirm(subject).can receive(:full_name).and_return("Dick Jones")
133
- expect(subject.full_name).to eq("Dick Jones")
134
- end
135
143
 
144
+ describe Person, "#full_name" do
145
+
146
+ it "returns something" do
147
+ expect(subject.full_name).to return("Dick Jones")
136
148
  end
137
149
 
138
150
  end
151
+
152
+
139
153
  """
140
154
 
155
+
141
156
  Scenario: For one matched and one unmatched expectation
142
157
  Given a file named "top_level_spec.rb" with:
143
158
  """ruby
@@ -148,8 +163,8 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
148
163
 
149
164
  it "starts with an introduction" do
150
165
  boss = Person.new('Dick', 'Jones')
151
- expect(boss).to receive(:full_name).and_return("Dick Jones")
152
- expect(boss).to receive(:title).and_return("Vice President")
166
+ allow(boss).to receive(:full_name).and_return("Dick Jones")
167
+ allow(boss).to receive(:title).and_return("Vice President")
153
168
  expect(boss.welcome).to eq "Welcome to OCP, I'm Vice President Dick Jones"
154
169
  end
155
170
 
@@ -162,7 +177,6 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
162
177
  describe "#full_name" do
163
178
 
164
179
  it "returns the correct value" do
165
- pending
166
180
  confirm(subject).can receive(:full_name).and_return("Dick Jones")
167
181
  # ...
168
182
  end
@@ -188,24 +202,16 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
188
202
 
189
203
  When I run `rspec top_level_spec.rb`
190
204
  Then it should pass with:
191
- """
205
+ """ruby
192
206
  Specs have been generated based on mocks you aren't currently testing.
193
207
  """
194
- And the file "generated_specs/person_spec.rb" should contain:
195
- """
196
- describe Person do
197
-
198
- describe "#title" do
199
-
200
- it "returns the correct value" do
201
- pending
202
- confirm(subject).can receive(:title).and_return("Vice President")
203
- expect(subject.title).to eq("Vice President")
204
- end
205
-
206
- end
207
-
208
- end
208
+ And the file "varys.yaml" should contain:
209
+ """yaml
210
+ ---
211
+ :untested_stubs:
212
+ - :class_name: Person
213
+ :method: title
214
+ :returns: Vice President
209
215
  """
210
216
 
211
217
  Scenario: For an expectation with parameters
@@ -221,7 +227,6 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
221
227
  describe "#full_name" do
222
228
 
223
229
  it "returns the correct value" do
224
- pending
225
230
  confirm(subject).can receive(:full_name).and_return("Dick Jones")
226
231
  expect(subject).to receive(:join_names).with("Dick", "Jones").and_return("Dick Jones")
227
232
  subject.full_name
@@ -254,22 +259,30 @@ Feature: Generating an RSpec Spec from an RSpec Expectation
254
259
 
255
260
  When I run `rspec top_level_spec.rb`
256
261
  Then it should pass with:
257
- """
262
+ """ruby
258
263
  Specs have been generated based on mocks you aren't currently testing.
259
264
  """
260
- And the file "generated_specs/person_spec.rb" should contain:
265
+ And the file "varys.yaml" should contain:
266
+ """yaml
267
+ ---
268
+ :untested_stubs:
269
+ - :class_name: Person
270
+ :method: join_names
271
+ :returns: Dick Jones
272
+ :arguments:
273
+ - Dick
274
+ - Jones
261
275
  """
262
- describe Person do
263
276
 
264
- describe "#join_names" do
265
-
266
- it "returns the correct value" do
267
- pending
268
- confirm(subject).can receive(:join_names).with("Dick", "Jones").and_return("Dick Jones")
269
- expect(subject.join_names("Dick", "Jones")).to eq("Dick Jones")
270
- end
277
+ And the file "generated_specs.rb" should contain:
278
+ """ruby
279
+ describe Person, "#join_names" do
271
280
 
281
+ it "returns something" do
282
+ expect(subject.join_names("Dick", "Jones")).to return("Dick Jones")
272
283
  end
273
284
 
274
285
  end
286
+
287
+
275
288
  """
data/features/readme.md CHANGED
@@ -1,4 +1,4 @@
1
- *Everything should be built top-down, except the first time - Alan
1
+ *Everything should be built top-down, except the first time 1. Alan
2
2
  Perlis*
3
3
 
4
4
  RSpec-Varys automatically generates RSpec specs from your mocked methods each time your suite is run.
@@ -7,4 +7,27 @@ This enables you to build your program from the top-down (or outside-in if
7
7
  your prefer) without having to manually keep track of which mocks have
8
8
  been validated.
9
9
 
10
- Available on [Github](https://github.com/ritchiey/rspec-varys)
10
+ Installation instructions can be found [here](https://github.com/ritchiey/rspec-varys).
11
+
12
+ A typical workflow using rspec-varys looks like this. Note, I haven't
13
+ written "and run your specs again" at the end of each step, that's
14
+ implied.
15
+
16
+ - if you have no failing specs and you need some new functionality, write a new top-level spec.
17
+
18
+ - if your specs are failing because your **spec** calls a non-existent function,
19
+ write the code for that function. Feel free to call methods that
20
+ don't exist yet.
21
+
22
+ - if your specs are failing because your **code** calls a non-existent function
23
+ stub that function out in the spec using `allow`.
24
+
25
+ - if your specs pass but varys generates new specs for untested stubs,
26
+ copy the generated specs into the appropriate spec file.
27
+
28
+ - if varys warns you about unneeded specs, delete those specs and any
29
+ code that can be removed without making other specs fail.
30
+
31
+ - if your specs pass but there are pending specs, pick one and remove
32
+ the `pending` statement.
33
+
@@ -1 +1,3 @@
1
1
  require 'aruba/cucumber'
2
+
3
+
data/lib/rspec/varys.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "rspec/varys/version"
2
2
  require "fileutils"
3
+ require 'yaml'
3
4
 
4
5
  module RSpec
5
6
  module Varys
@@ -26,11 +27,25 @@ module RSpec
26
27
  {
27
28
  class_name: class_name,
28
29
  message: message,
29
- args: [],
30
- return_value: "Dick Jones"
30
+ args: args,
31
+ return_value: return_value
31
32
  }
32
33
  end
33
34
 
35
+ def args
36
+ customization = customizations.find{|c| c.instance_variable_get('@method_name') == :with}
37
+ (customization && customization.instance_variable_get('@args')) || []
38
+ end
39
+
40
+ def return_value
41
+ customization = customizations.find{|c| c.instance_variable_get('@method_name') == :and_return}
42
+ customization && customization.instance_variable_get('@args').first
43
+ end
44
+
45
+ def customizations
46
+ @ability.instance_variable_get('@recorded_customizations')
47
+ end
48
+
34
49
  def class_name
35
50
  @object.class.name
36
51
  end
@@ -121,7 +136,7 @@ module RSpec::Varys
121
136
  end
122
137
 
123
138
  def self.params(args)
124
- args.map{|a| serialize(a)}.join(", ")
139
+ args.map{|a| serialize(a)}.join(", ")
125
140
  end
126
141
 
127
142
  def self.parameters(spec)
@@ -133,20 +148,35 @@ module RSpec::Varys
133
148
  end
134
149
 
135
150
  def self.print_report
136
- dest_path = "generated_specs"
137
- FileUtils.mkdir_p dest_path
138
- generated_specs.each do |class_name, specs|
139
- File.open("#{dest_path}/#{underscore class_name}_spec.rb", 'w') do |file|
140
- file.write "describe #{class_name} do\n\n"
141
- specs.each do |spec|
142
- file.write(spec)
143
- end
144
- file.write "end"
145
- end
151
+ open_yaml_file do |yaml_file|
152
+ yaml_file.write YAML.dump(report)
146
153
  end
147
154
  puts "Specs have been generated based on mocks you aren't currently testing."
148
155
  end
149
156
 
157
+ def self.report
158
+ {
159
+ untested_stubs: unconfirmed_messages.map do |call|
160
+ {
161
+ class_name: call[:class_name],
162
+ method: call[:message].to_s,
163
+ returns: call[:return_value]
164
+ }.merge(arguments_if_any(call))
165
+ end
166
+ }
167
+ end
168
+
169
+ def self.arguments_if_any(call)
170
+ call[:args].length > 0 ? { arguments: call[:args] } : { }
171
+ end
172
+
173
+ def self.open_yaml_file
174
+ File.open("varys.yaml", 'w') do |io|
175
+ yield io
176
+ end
177
+ end
178
+
179
+
150
180
  def self.unconfirmed_messages
151
181
  recorded_messages - confirmed_messages
152
182
  end
@@ -0,0 +1,51 @@
1
+ class RSpec::Varys::RSpecGenerator
2
+
3
+ def self.run
4
+
5
+ specs = YAML.load(File.read "varys.yaml")
6
+
7
+ File.open('generated_specs.rb', 'w') do |file|
8
+ process_specs(specs, file)
9
+ end
10
+
11
+ end
12
+
13
+ def self.process_specs(specs, file)
14
+ specs[:untested_stubs].each do |spec|
15
+ file.puts <<-EOF
16
+ describe #{spec[:class_name]}, "##{spec[:method]}" do
17
+
18
+ it "returns something" do
19
+ expect(subject.#{spec[:method]}#{args_if_any(spec)}).to return(#{serialize spec[:returns]})
20
+ end
21
+
22
+ end
23
+
24
+
25
+ EOF
26
+ end
27
+ end
28
+
29
+ def self.args_if_any(call)
30
+ args = call[:arguments]
31
+ (args && args.length > 0) ? "(#{args.map{|a| serialize a}.join ', '})" : ""
32
+ end
33
+
34
+ # Attempt to recreate the source-code to represent this argument in the setup
35
+ # for our generated spec.
36
+ def self.serialize(arg)
37
+ if %w(Array Hash Float Fixnum String).include? arg.class.name
38
+ arg.pretty_inspect.chop
39
+ else
40
+ guess_constructor arg
41
+ end
42
+ end
43
+
44
+ # Don't recognise the type so we don't know how to recreate it
45
+ # in source code. So we'll take a guess at what might work and
46
+ # let the user fix it up if necessary.
47
+ def self.guess_constructor(arg)
48
+ "#{arg.class.name}.new(#{serialize(arg.to_s)})"
49
+ end
50
+
51
+ end
@@ -1,5 +1,5 @@
1
1
  module Rspec
2
2
  module Varys
3
- VERSION = "0.0.3"
3
+ VERSION = "0.1.0"
4
4
  end
5
5
  end
@@ -34,6 +34,7 @@ describe RSpec::Varys do
34
34
  { class_name: 'Object', message: :a_message, args: [:a_parameter], return_value: 42 }
35
35
  ])
36
36
  end
37
+
37
38
  end
38
39
 
39
40
  describe ".confirmed_messages" do
@@ -50,6 +51,17 @@ describe RSpec::Varys do
50
51
  }])
51
52
  end
52
53
 
54
+ it "parses parameters" do
55
+ described_class.reset
56
+ confirm(Person.new 'Dick', 'Jones').can receive(:full_name).with(:blah).and_return("Dick Jones")
57
+ expect(described_class.confirmed_messages).to match_array([{
58
+ class_name: 'Person',
59
+ message: :full_name,
60
+ args: [:blah],
61
+ return_value: "Dick Jones"
62
+ }])
63
+ end
64
+
53
65
  end
54
66
 
55
67
  it "records the messages sent to a spy" do
@@ -0,0 +1,4 @@
1
+
2
+ require 'pry'
3
+ Dir.glob(::File.expand_path('../support/*.rb', __FILE__)).each { |f| require_relative f }
4
+ Dir.glob(::File.expand_path('../../lib/*.rb', __FILE__)).each { |f| require_relative f }
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+ require_relative '../../lib/rspec/varys/rspec_generator'
3
+
4
+ describe RSpec::Varys::RSpecGenerator do
5
+
6
+ describe ".process_specs" do
7
+
8
+ context "given a file YAML file with one missing spec with arguments" do
9
+ let(:specs) {
10
+ YAML.load <<-SPECS
11
+ ---
12
+ :untested_stubs:
13
+ - :class_name: Person
14
+ :method: full_name
15
+ :arguments:
16
+ - Dick
17
+ - Jones
18
+ :returns: Dick Jones
19
+ SPECS
20
+ }
21
+
22
+ it "generates the spec" do
23
+ output = ""
24
+ StringIO.open(output, 'w') do |file|
25
+ described_class.process_specs(specs, file)
26
+ end
27
+ expect(output).to eq <<-EOF
28
+ describe Person, "#full_name" do
29
+
30
+ it "returns something" do
31
+ expect(subject.full_name("Dick", "Jones")).to return("Dick Jones")
32
+ end
33
+
34
+ end
35
+
36
+
37
+ EOF
38
+ end
39
+ end
40
+
41
+
42
+ context "given a file YAML file with one missing spec" do
43
+ let(:specs) {
44
+ YAML.load <<-SPECS
45
+ ---
46
+ :untested_stubs:
47
+ - :class_name: Person
48
+ :method: full_name
49
+ :returns: Dick Jones
50
+ SPECS
51
+ }
52
+
53
+ it "generates the spec" do
54
+ output = ""
55
+ StringIO.open(output, 'w') do |file|
56
+ described_class.process_specs(specs, file)
57
+ end
58
+ expect(output).to eq <<-EOF
59
+ describe Person, "#full_name" do
60
+
61
+ it "returns something" do
62
+ expect(subject.full_name).to return("Dick Jones")
63
+ end
64
+
65
+ end
66
+
67
+
68
+ EOF
69
+ end
70
+ end
71
+
72
+ end
73
+
74
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-varys
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ritchie Young
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-27 00:00:00.000000000 Z
11
+ date: 2015-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -108,7 +108,8 @@ description: Automatically track which assumptions you've made in the form or mo
108
108
  and stubs actually work.
109
109
  email:
110
110
  - ritchiey@gmail.com
111
- executables: []
111
+ executables:
112
+ - genspecs
112
113
  extensions: []
113
114
  extra_rdoc_files: []
114
115
  files:
@@ -119,13 +120,17 @@ files:
119
120
  - LICENSE.txt
120
121
  - README.md
121
122
  - Rakefile
123
+ - bin/genspecs
122
124
  - features/generating_specs.feature
123
125
  - features/readme.md
124
- - features/support/env.rb
126
+ - features/support/external.rb
125
127
  - lib/rspec/varys.rb
128
+ - lib/rspec/varys/rspec_generator.rb
126
129
  - lib/rspec/varys/version.rb
127
130
  - rspec-varys.gemspec
128
131
  - spec/rspec/varys_spec.rb
132
+ - spec/spec_helper.rb
133
+ - spec/varys/rspec_generator_spec.rb
129
134
  homepage: https://github.com/ritchiey/rspec-varys
130
135
  licenses:
131
136
  - MIT
@@ -153,6 +158,8 @@ summary: Generate RSpec specs from intelligence gathered from doubles and spies.
153
158
  test_files:
154
159
  - features/generating_specs.feature
155
160
  - features/readme.md
156
- - features/support/env.rb
161
+ - features/support/external.rb
157
162
  - spec/rspec/varys_spec.rb
163
+ - spec/spec_helper.rb
164
+ - spec/varys/rspec_generator_spec.rb
158
165
  has_rdoc: