mattwynne-cucover 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +31 -2
- data/lib/cucover.rb +57 -9
- metadata +3 -22
data/README.markdown
CHANGED
@@ -6,14 +6,43 @@ What does it mean for Cucumber to be lazy? It will only run a feature if it need
|
|
6
6
|
|
7
7
|
How does it decide whether it needs to run a feature? Every time you run a feature using Cucover, it watches the code in your application that is executed, and remembers. The next time you run Cucover, it skips a feature if the source files (or the feature itself) have not been changed since it was last run.
|
8
8
|
|
9
|
+
## Features
|
10
|
+
|
11
|
+
* Uses RCov to map features to covered source files
|
12
|
+
* Patches Rails to also map features to covered .erb templates
|
13
|
+
|
9
14
|
## Installation and Usage
|
10
15
|
|
11
|
-
|
16
|
+
Something like this, as I haven't figured out the dependencies yet for the gem:
|
17
|
+
|
18
|
+
sudo gem install spicycode-rcov
|
19
|
+
sudo gem install mattwynne-cucover
|
12
20
|
|
13
21
|
To run your features lazily, just use the cucover binary instead of cucumber. Use the same command-line options as usual, they are all passed directly to cucumber. No magic to see here, just a little gentle duck-punching.
|
14
22
|
|
15
23
|
## Limitations
|
16
24
|
|
17
|
-
* Cucover uses RCov to watch the code executed by each feature. RCov does not report ERB view templates so Rails views, for example, that are touched will not cause any features to be re-run.
|
18
25
|
* Anything that runs out of process will not be covered, and therefore cannot trigger a re-run, so if you use Cucumber to drive Selenium, for example, you're out of luck.
|
19
26
|
* This is very new and experimental. There may be bugs. Feedback is welcome via github messages.
|
27
|
+
|
28
|
+
## Todo
|
29
|
+
* The features for cucuover itself seem to flicker (intermittently fail). This is probably due to timing issues when figuring out if a file is dirty.
|
30
|
+
* Consider making failing features run-run even when they're not dirty, just for the good old red-bar feel
|
31
|
+
|
32
|
+
## Similar 'Selective Testing' Tools
|
33
|
+
|
34
|
+
* JTestMe
|
35
|
+
* http://xircles.codehaus.org/projects/jtestme
|
36
|
+
* [Agile2008 conference submission](http://submissions.agile2008.org/node/3435)
|
37
|
+
* Infinitest
|
38
|
+
* http://code.google.com/p/infinitest/
|
39
|
+
* Contact: [Ben Rady](http://submissions.agile2008.org/node/377)
|
40
|
+
* Google Testar
|
41
|
+
* http://code.google.com/p/google-testar/
|
42
|
+
* Contact: Misha Dmitriev
|
43
|
+
* Clover test optimization
|
44
|
+
* http://www.atlassian.com/software/clover/features/optimization.jsp
|
45
|
+
* JUnitMax
|
46
|
+
* a selective testing tool by [Kent Beck](http://www.threeriversinstitute.org/blog)
|
47
|
+
* http://junitmax.com/
|
48
|
+
|
data/lib/cucover.rb
CHANGED
@@ -6,6 +6,15 @@ require 'rcov'
|
|
6
6
|
|
7
7
|
module Cucover
|
8
8
|
|
9
|
+
class << self
|
10
|
+
def record(file)
|
11
|
+
additional_covered_files << file
|
12
|
+
end
|
13
|
+
def additional_covered_files
|
14
|
+
@additional_covered_files ||= []
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
9
18
|
class SourceFileCache
|
10
19
|
def initialize(feature_file)
|
11
20
|
@feature_file = feature_file
|
@@ -22,10 +31,8 @@ module Cucover
|
|
22
31
|
File.exist?(cache_filename)
|
23
32
|
end
|
24
33
|
|
25
|
-
def
|
26
|
-
|
27
|
-
File.mtime(Dir.pwd + '/' + source_file.strip) > time
|
28
|
-
end
|
34
|
+
def any_dirty_files?
|
35
|
+
not dirty_files.empty?
|
29
36
|
end
|
30
37
|
|
31
38
|
def time
|
@@ -33,6 +40,12 @@ module Cucover
|
|
33
40
|
end
|
34
41
|
|
35
42
|
private
|
43
|
+
|
44
|
+
def dirty_files
|
45
|
+
source_files.select do |source_file|
|
46
|
+
File.mtime(Dir.pwd + '/' + source_file.strip) >= time
|
47
|
+
end
|
48
|
+
end
|
36
49
|
|
37
50
|
def source_files
|
38
51
|
result = []
|
@@ -53,6 +66,7 @@ module Cucover
|
|
53
66
|
|
54
67
|
def accept(visitor)
|
55
68
|
return unless dirty?
|
69
|
+
Cucover.additional_covered_files.clear
|
56
70
|
analyzer.run_hooked do
|
57
71
|
super
|
58
72
|
end
|
@@ -63,8 +77,12 @@ module Cucover
|
|
63
77
|
|
64
78
|
def dirty?
|
65
79
|
return true unless source_files_cache.exists?
|
66
|
-
return true if
|
67
|
-
|
80
|
+
return true if changed_since_last_run?
|
81
|
+
source_files_cache.any_dirty_files?
|
82
|
+
end
|
83
|
+
|
84
|
+
def changed_since_last_run?
|
85
|
+
File.mtime(@file) >= source_files_cache.time
|
68
86
|
end
|
69
87
|
|
70
88
|
def source_files_cache
|
@@ -76,9 +94,11 @@ module Cucover
|
|
76
94
|
end
|
77
95
|
|
78
96
|
def analyzed_files
|
79
|
-
normalized_files
|
80
|
-
|
81
|
-
|
97
|
+
normalized_files.reject{ |f| boring?(f) }.sort
|
98
|
+
end
|
99
|
+
|
100
|
+
def normalized_files
|
101
|
+
(analyzer.analyzed_files + Cucover.additional_covered_files.uniq).map{ |f| File.expand_path(f).gsub(/^#{Dir.pwd}\//, '') }
|
82
102
|
end
|
83
103
|
|
84
104
|
def boring?(file)
|
@@ -95,6 +115,30 @@ module Cucover
|
|
95
115
|
super feature.extend(LazyFeature)
|
96
116
|
end
|
97
117
|
end
|
118
|
+
|
119
|
+
module Rails
|
120
|
+
class << self
|
121
|
+
def patch_if_necessary
|
122
|
+
return if @patched
|
123
|
+
return unless defined?(ActionView)
|
124
|
+
|
125
|
+
ActionView::Template.instance_eval do
|
126
|
+
def new(*args)
|
127
|
+
super(*args).extend(Cucover::Rails::RecordsRenders)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
@patched = true
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
module RecordsRenders
|
136
|
+
def render
|
137
|
+
Cucover.record(@filename)
|
138
|
+
super
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
98
142
|
end
|
99
143
|
|
100
144
|
module Cucumber
|
@@ -108,3 +152,7 @@ module Cucumber
|
|
108
152
|
end
|
109
153
|
end
|
110
154
|
end
|
155
|
+
|
156
|
+
Before do
|
157
|
+
Cucover::Rails.patch_if_necessary
|
158
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mattwynne-cucover
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Wynne
|
@@ -11,27 +11,8 @@ cert_chain: []
|
|
11
11
|
|
12
12
|
date: 2009-03-18 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
name: cucumber
|
17
|
-
type: :runtime
|
18
|
-
version_requirement:
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: "0.2"
|
24
|
-
version:
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
|
-
name: rcov
|
27
|
-
type: :runtime
|
28
|
-
version_requirement:
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 0.8.1.5
|
34
|
-
version:
|
14
|
+
dependencies: []
|
15
|
+
|
35
16
|
description: Cucover is a thin wrapper for Cucumber which makes it lazy.
|
36
17
|
email: matt@mattwynne.net
|
37
18
|
executables: []
|