lemon 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY CHANGED
@@ -1,17 +1,20 @@
1
1
  = RELEASE HISTORY
2
2
 
3
+ == 0.8.0 / 2010-06-21
4
+
5
+ This release removes coverage information from testing. Coverage can be time consuming, but running test should be as fast as possbile. For this reason coverage and testing are kept two independent activities. This release also adds some test coverage for Lemon itself via Cucumber.
6
+
7
+ Changes:
8
+
9
+ * Separated coverage from testing completely.
10
+ * Test generator defaults to public methods only.
11
+
12
+
3
13
  == 0.7.0 / 2010-05-04
4
14
 
5
- This release fixes issue with coverage reports. To do this
6
- we have interoduced the +Covers+ method. This allows Lemon
7
- to distingush between code that is inteded to be covered
8
- by the tests and mere support code.
15
+ This release fixes issue with coverage reports. To do this we have interoduced the +Covers+ method. This allows Lemon to distingush between code that is inteded to be covered by the tests and mere support code.
9
16
 
10
- Keep in mind that there is no perfect way to handle coverage.
11
- Even with the distiction the +Covers+ method provides, coverage
12
- might not be reported exactly as desired. Other techinques can
13
- be used to refine coverage however, such a preloading embedded
14
- support libraries.
17
+ Keep in mind that there is no perfect way to handle coverage. Even with the distiction the +Covers+ method provides, coverage might not be reported exactly as desired. Other techinques can be used to refine coverage however, such a preloading embedded support libraries.
15
18
 
16
19
  Changes:
17
20
 
@@ -21,8 +24,7 @@ Changes:
21
24
 
22
25
  == 0.6.0 / 2010-03-06
23
26
 
24
- This release adds coverage reporting to testing and improves
25
- the generator.
27
+ This release adds coverage reporting to testing and improves the generator.
26
28
 
27
29
  Changes:
28
30
 
@@ -33,10 +35,7 @@ Changes:
33
35
 
34
36
  == 0.5.0 / 2009-12-31
35
37
 
36
- This is the initial public release of Lemon. Lemon is
37
- still under development and should be considered betaware,
38
- but it's API is stable and the system usable enough to
39
- warrant a release.
38
+ This is the initial public release of Lemon. Lemon is still under development and should be considered betaware, but it's API is stable and the system usable enough to warrant a release.
40
39
 
41
40
  Changes:
42
41
 
data/PROFILE ADDED
@@ -0,0 +1,16 @@
1
+ ---
2
+ title: Lemon
3
+ suite: proutils
4
+ copyright: Copyright 2009 Thomas Sawyer
5
+ license: MIT
6
+ summary: Pucker-tight Unit Testing
7
+ authors: Thomas Sawyer
8
+ contact: proutils@googlegroups.com
9
+
10
+ description:
11
+ Lemon is a unit testing framework that tightly correlates
12
+ class to test case and method to test unit.
13
+
14
+ resources:
15
+ homepage: http://proutils.github.com/lemon
16
+ repository: git://github.com/proutils/lemon.git
data/README.rdoc CHANGED
@@ -6,16 +6,9 @@
6
6
 
7
7
  == DESCRIPTION
8
8
 
9
- Lemon is a Unit Testing Framework that enforces a test case
10
- construction mirroring the class/module and method design
11
- of the target system. Arguably this promotes the proper
12
- technique for unit testing and helps ensure good test
13
- coverage.
9
+ Lemon is a Unit Testing Framework that enforces a test case construction mirroring the class/module and method design of the target system. Arguably this promotes the proper technique for unit testing and helps ensure good test coverage.
14
10
 
15
- The difference between unit testing and functional testing, and
16
- all other forms of testing for that matter, lies in where the
17
- *concern* lies. The concern of unit testing are the concerns
18
- of unit tests -- the individual methods.
11
+ The difference between unit testing and functional testing, and all other forms of testing for that matter, lies in where the *concern* lies. The concern of unit testing are the concerns of unit tests -- the individual methods.
19
12
 
20
13
 
21
14
  == HOW TO USE
@@ -39,12 +32,9 @@ The simplist test case would be written as follows:
39
32
  end
40
33
  end
41
34
 
42
- The +Covers+ method works just like +require+ with the exception
43
- that loading the file does not occur until just before the tests
44
- are run. This allows Lemon to cacluate accurate coverage reports.
35
+ The +Covers+ method works just like +require+ with the exception that loading the file does not occur until just before the tests are run. This allows Lemon to cacluate accurate coverage reports.
45
36
 
46
- As tests grow, we might need to organize them into special concerns.
47
- For this Lemon provides the #Concern method.
37
+ As tests grow, we might need to organize them into special concerns. For this Lemon provides the #Concern method.
48
38
 
49
39
  Covers 'mylib'
50
40
 
@@ -63,35 +53,23 @@ To run tests use the +lemon+ command-line utility.
63
53
 
64
54
  $ lemon test/cases/name_case.rb
65
55
 
66
- Normal output is typical <i>dot-progress</i>. For verbose output, use
67
- the <tt>--verbose</tt> or <tt>-v</tt> option.
56
+ Normal output is typical <i>dot-progress</i>. For verbose output, use the <code>--verbose</code> or <code>-v</code> option.
68
57
 
69
58
  $ lemon -v test/cases/name_case.rb
70
59
 
71
60
  === Checking Test Coverage
72
61
 
73
- Lemon can check test coverage by loading your target system and
74
- comparing it to your tests.
62
+ Lemon can check test coverage by loading your target system and comparing it to your tests. To do this suppy the <code>lemon</code> command the <code>--coverage</code> or <code>-c</code> option.
75
63
 
76
64
  $ lemon --coverage -Ilib test/cases/
77
65
 
78
66
  === Generating Test Skeletons
79
67
 
80
- Because of the one to one correspondance of case-unit to class-method, Lemon can
81
- also generate test scaffolding for previously written code. To do this, use the
82
- <tt>--generate</tt> option and provide the lib location, or files, of the
83
- scripts for which to generate test scaffolding, and the output location for
84
- the test scripts.
68
+ Because of the one to one correspondance of case-unit to class-method, Lemon can also generate test scaffolding for previously written code. To do this, use the <code>--generate</code> or <code>-g</code> option and provide the lib location, or files, of the scripts for which to generate test scaffolding, and the output location for the test scripts.
85
69
 
86
70
  $ lemon --generate -Ilib test/cases/
87
71
 
88
- Generating test case scaffodling from code will undoubtedly strike test-driven developers
89
- as a case of putting the cart before the horse. However, it is not unreasonable to argue
90
- that high-level, behavior-driven, functional testing frameworks, such as Q.E.D. and
91
- Cucumber are better suited to test-first methodologies. While test-driven development
92
- can obviously be done with Lemon, unit-testing is more appropriate for testing specific,
93
- critical protions of code, or for achieving full test coverage for mission critical
94
- applications.
72
+ Generating test case scaffodling from code will undoubtedly strike test-driven developers as a case of putting the cart before the horse. However, it is not unreasonable to argue that high-level, behavior-driven, functional testing frameworks, such as Q.E.D. and Cucumber are better suited to test-first methodologies. While test-driven development can obviously be done with Lemon, unit-testing is more appropriate for testing specific, critical protions of code, or for achieving full test coverage for mission critical applications.
95
73
 
96
74
 
97
75
  == COPYRIGHT
data/REQUIRE ADDED
@@ -0,0 +1,9 @@
1
+ development:
2
+ - syckle
3
+ - box
4
+
5
+ development/test:
6
+ - cucumber
7
+ - ae
8
+ - aruba
9
+
data/VERSION ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ name : lemon
3
+ major: 0
4
+ minor: 8
5
+ patch: 0
6
+ date : 2010-06-21
@@ -0,0 +1,65 @@
1
+ Feature: Coverage
2
+ As a developer
3
+ In order to improve test coverge
4
+ I want to able to write tests with coverage in mind
5
+ And receive effective coverage reports
6
+
7
+ Scenario: Complete Example Case
8
+ Given a directory named "example"
9
+ Given a file named "example/lib/example.rb" with:
10
+ """
11
+ class X
12
+ def a; "a"; end
13
+ def b; "b"; end
14
+ def c; "c"; end
15
+ end
16
+ class Y
17
+ def q; "q"; end
18
+ end
19
+ """
20
+ Given a file named "example/test/case_complete.rb" with:
21
+ """
22
+ Covers 'example'
23
+ TestCase X do
24
+ Unit :a => "Returns a String" do ; end
25
+ Unit :b => "Returns a String" do ; end
26
+ Unit :c => "Returns a String" do ; end
27
+ end
28
+ TestCase Y do
29
+ Unit :q => "Returns a String" do ; end
30
+ end
31
+ """
32
+ When I cd to "example"
33
+ And I run "lemon -c -Ilib test/case_complete.rb"
34
+ Then the stdout should contain "0 uncovered cases"
35
+ And the stdout should contain "0 uncovered units"
36
+ And the stdout should contain "0 undefined units"
37
+
38
+ Scenario: Incomplete Example Case
39
+ Given a directory named "example"
40
+ Given a file named "example/lib/example.rb" with:
41
+ """
42
+ class X
43
+ def a; "a"; end
44
+ def b; "b"; end
45
+ def c; "c"; end
46
+ end
47
+ class Y
48
+ def q; "q"; end
49
+ end
50
+ """
51
+ Given a file named "example/test/case_complete.rb" with:
52
+ """
53
+ Covers 'example'
54
+ TestCase X do
55
+ Unit :a => "Returns a String" do ; end
56
+ Unit :b => "Returns a String" do ; end
57
+ Unit :d => "Returns a String" do ; end
58
+ end
59
+ """
60
+ When I cd to "example"
61
+ And I run "lemon -c -Ilib test/case_complete.rb"
62
+ Then the stdout should contain "1 uncovered cases"
63
+ And the stdout should contain "1 uncovered units"
64
+ And the stdout should contain "1 undefined units"
65
+
@@ -0,0 +1,66 @@
1
+ Feature: Coverage
2
+ As a developer
3
+ In order to improve test coverge
4
+ I want to able to write unit tests that target methods
5
+ And run those tests
6
+
7
+ Scenario: Complete Example Case
8
+ Given a directory named "example"
9
+ Given a file named "example/lib/example.rb" with:
10
+ """
11
+ class X
12
+ def a; "a"; end
13
+ def b; "b"; end
14
+ def c; "c"; end
15
+ end
16
+ class Y
17
+ def q; "q"; end
18
+ end
19
+ """
20
+ Given a file named "example/test/case_complete.rb" with:
21
+ """
22
+ Covers 'example'
23
+ TestCase X do
24
+ Unit :a => "Returns a String" do ; X.new.a.assert.is_a?(String) ; end
25
+ Unit :b => "Returns a String" do ; X.new.b.assert.is_a?(String) ; end
26
+ Unit :c => "Returns a String" do ; X.new.c.assert.is_a?(String) ; end
27
+ end
28
+ TestCase Y do
29
+ Unit :q => "Returns a String" do ; Y.new.q.assert.is_a?(String) ; end
30
+ end
31
+ """
32
+ When I cd to "example"
33
+ And I run "lemon -g -u -Ilib test/case_complete.rb"
34
+ Then the stdout should not contain "Unit :a"
35
+ And the stdout should not contain "Unit :b"
36
+ And the stdout should not contain "Unit :c"
37
+ And the stdout should not contain "Unit :q"
38
+
39
+ Scenario: Incomplete Example Case
40
+ Given a directory named "example"
41
+ Given a file named "example/lib/example.rb" with:
42
+ """
43
+ class X
44
+ def a; "a"; end
45
+ def b; "b"; end
46
+ def c; "c"; end
47
+ end
48
+ class Y
49
+ def q; "q"; end
50
+ end
51
+ """
52
+ Given a file named "example/test/case_complete.rb" with:
53
+ """
54
+ Covers 'example'
55
+ TestCase X do
56
+ Unit :a => "Returns a String" do ; X.new.a.assert.is_a?(String) ; end
57
+ Unit :b => "Returns a String" do ; X.new.b.assert.is_a?(Fixnum) ; end
58
+ Unit :d => "Returns a String" do ; X.new.d.assert.is_a?(String) ; end
59
+ end
60
+ """
61
+ When I cd to "example"
62
+ And I run "lemon -g -u -Ilib test/case_complete.rb"
63
+ Then the stdout should not contain "Unit :a"
64
+ And the stdout should not contain "Unit :b"
65
+ And the stdout should contain "Unit :c"
66
+
@@ -0,0 +1 @@
1
+ require 'ae'
@@ -0,0 +1 @@
1
+ require 'aruba'
@@ -0,0 +1,67 @@
1
+ Feature: Coverage
2
+ As a developer
3
+ In order to improve test coverge
4
+ I want to able to write unit tests that target methods
5
+ And run those tests
6
+
7
+ Scenario: Complete Example Case
8
+ Given a directory named "example"
9
+ Given a file named "example/lib/example.rb" with:
10
+ """
11
+ class X
12
+ def a; "a"; end
13
+ def b; "b"; end
14
+ def c; "c"; end
15
+ end
16
+ class Y
17
+ def q; "q"; end
18
+ end
19
+ """
20
+ Given a file named "example/test/case_complete.rb" with:
21
+ """
22
+ Covers 'example'
23
+ TestCase X do
24
+ Unit :a => "Returns a String" do ; X.new.a.assert.is_a?(String) ; end
25
+ Unit :b => "Returns a String" do ; X.new.b.assert.is_a?(String) ; end
26
+ Unit :c => "Returns a String" do ; X.new.c.assert.is_a?(String) ; end
27
+ end
28
+ TestCase Y do
29
+ Unit :q => "Returns a String" do ; Y.new.q.assert.is_a?(String) ; end
30
+ end
31
+ """
32
+ When I cd to "example"
33
+ And I run "lemon -Ilib -v test/case_complete.rb"
34
+ Then the stdout should contain "4 tests"
35
+ And the stdout should contain "4 pass"
36
+ And the stdout should contain "0 fail"
37
+ And the stdout should contain "0 err"
38
+
39
+ Scenario: Incomplete Example Case
40
+ Given a directory named "example"
41
+ Given a file named "example/lib/example.rb" with:
42
+ """
43
+ class X
44
+ def a; "a"; end
45
+ def b; "b"; end
46
+ def c; "c"; end
47
+ end
48
+ class Y
49
+ def q; "q"; end
50
+ end
51
+ """
52
+ Given a file named "example/test/case_complete.rb" with:
53
+ """
54
+ Covers 'example'
55
+ TestCase X do
56
+ Unit :a => "Returns a String" do ; X.new.a.assert.is_a?(String) ; end
57
+ Unit :b => "Returns a String" do ; X.new.b.assert.is_a?(Fixnum) ; end
58
+ Unit :d => "Returns a String" do ; X.new.d.assert.is_a?(String) ; end
59
+ end
60
+ """
61
+ When I cd to "example"
62
+ And I run "lemon -Ilib -v test/case_complete.rb"
63
+ Then the stdout should contain "3 tests"
64
+ And the stdout should contain "1 pass"
65
+ And the stdout should contain "1 fail"
66
+ And the stdout should contain "1 err"
67
+
data/lib/lemon.rb CHANGED
@@ -1 +1,2 @@
1
1
  require 'lemon/runner'
2
+ require 'lemon/coverage'
data/lib/lemon/command.rb CHANGED
@@ -1,22 +1,184 @@
1
- require 'lemon/command/test'
2
- require 'lemon/command/coverage'
3
- require 'lemon/command/generate'
4
-
5
1
  module Lemon
6
- module Command
7
-
8
- # Factory method to initialize and run choosen sub-command.
9
- def self.run
10
- cmd = Abstract.commands.find do |command_class|
11
- /^#{ARGV.first}/ =~ command_class.subcommand
12
- #[command_class.options].flatten.find do |subcmd|
13
- # #ARGV.delete(opt)
14
- # /^#{ARGV.first}/ =~ subcmd
15
- #end
16
- end
17
- ARGV.shift if cmd
18
- cmd ? cmd.run : Command::Test.run
2
+ require 'lemon'
3
+ require 'optparse'
4
+
5
+ # Lemon Command-line tool.
6
+ class Command
7
+
8
+ # Initialize and run.
9
+ def self.run
10
+ new.run
11
+ end
12
+
13
+ # New Command instance.
14
+ def initialize
15
+ @command = :test
16
+ @format = nil
17
+ @requires = []
18
+ @includes = []
19
+ @namespaces = []
20
+ @uncovered = false
21
+ @public_only = true
22
+ end
23
+
24
+ #
25
+ attr_accessor :command
26
+
27
+ #
28
+ attr_accessor :format
29
+
30
+ #
31
+ attr_accessor :requires
32
+
33
+ #
34
+ attr_accessor :includes
35
+
36
+ #
37
+ attr_accessor :namespaces
38
+
39
+ #
40
+ attr_accessor :uncovered
41
+
42
+ #
43
+ attr_accessor :public_only
44
+
45
+
46
+ # Get or set librarires to pre-require.
47
+ def requires(*paths)
48
+ @requires.concat(paths) unless paths.empty?
49
+ @requires
50
+ end
51
+
52
+ # Get or set paths to include in $LOAD_PATH.
53
+ def includes(*paths)
54
+ @includes.concat(paths) unless paths.empty?
55
+ @includes
56
+ end
57
+
58
+ #
59
+ def namespaces(*names)
60
+ @namespaces.concat(names) unless names.empty?
61
+ @namespaces
62
+ end
63
+
64
+ # Instance of OptionParser.
65
+ def parser
66
+ @parser ||= OptionParser.new do |opt|
67
+ opt.banner = "lemon [options] [files ...]"
68
+ opt.separator("Run unit tests, check coverage and generate test scaffolding.")
69
+ opt.separator " "
70
+ opt.separator("COMMAND OPTIONS (choose one):")
71
+ opt.on('--test', '-t', "run unit tests [default]") do
72
+ self.command = :test
73
+ end
74
+ opt.on('--coverage', '-c', "provide test coverage analysis") do
75
+ self.command = :cover
76
+ end
77
+ opt.on('--generate', '-g', "generate unit test scaffolding") do
78
+ self.command = :generate
79
+ end
80
+ opt.separator " "
81
+ opt.separator("COMMON OPTIONS:")
82
+ opt.on("--namespace", "-n NAME", "limit testing/coverage to namespace") do |name|
83
+ namespaces(name)
84
+ end
85
+ opt.on('--format', '-f TYPE', "select output format") do |type|
86
+ self.format = type
87
+ end
88
+ opt.on('--verbose', '-v', "select verbose report format") do |type|
89
+ self.format = :verbose
90
+ end
91
+ opt.on('--outline', '-o', "select outline report format") do |type|
92
+ self.format = :outline
93
+ end
94
+ opt.separator " "
95
+ opt.separator("COVERAGE OPTIONS:")
96
+ opt.on('--private', '-p', "include private and protected methods") do
97
+ self.public_only = false
98
+ end
99
+ opt.separator " "
100
+ opt.separator("GENERATOR OPTIONS:")
101
+ opt.on("--uncovered", "-u", "only include missing units of uncovered methods") do
102
+ self.uncovered = true
103
+ end
104
+ opt.separator " "
105
+ opt.separator("SYSTEM OPTIONS:")
106
+ opt.on("-r [FILES]" , 'files to require (before doing anything else)') do |files|
107
+ files = files.split(/[:;]/)
108
+ requires(*files)
109
+ end
110
+ opt.on("-I [PATH]" , 'locations to add to $LOAD_PATH') do |path|
111
+ paths = path.split(/[:;]/)
112
+ includes(*paths)
113
+ end
114
+ opt.on("--debug" , 'turn on debugging mode') do
115
+ $DEBUG = true
116
+ end
117
+ opt.on_tail('--help', '-h', 'show this help message') do
118
+ puts opt
119
+ exit
120
+ end
121
+ end
122
+ end
123
+
124
+ # Run command.
125
+ def run
126
+ parser.parse!
127
+ __send__(@command)
128
+ end
129
+
130
+ # Run unit tests.
131
+ def test
132
+ require 'lemon/runner'
133
+
134
+ files = ARGV.dup
135
+
136
+ includes.each{ |path| $LOAD_PATH.unshift(path) }
137
+ requires.each{ |path| require(path) }
138
+
139
+ #suite = Lemon::Test::Suite.new(files, :cover=>cover)
140
+ #runner = Lemon::Runner.new(suite, :format=>format, :cover=>cover, :namespaces=>namespaces)
141
+
142
+ suite = Lemon::Test::Suite.new(files)
143
+ runner = Lemon::Runner.new(suite, :format=>format, :namespaces=>namespaces)
144
+
145
+ runner.run
146
+ end
147
+
148
+ # Ouput coverage report.
149
+ def cover
150
+ test_files = ARGV.dup
151
+ load_files = []
152
+
153
+ includes.each{ |path| $LOAD_PATH.unshift(path) }
154
+ requires.each{ |path| require(path) }
155
+
156
+ suite = Lemon::Test::Suite.new(test_files, :cover=>true)
157
+ coverage = Lemon::Coverage.new(suite, namespaces, :public=>public_only)
158
+
159
+ coverage.format(format)
160
+ end
161
+
162
+ # Generate test templates.
163
+ def generate
164
+ test_files = ARGV.dup
165
+
166
+ includes.each{ |path| $LOAD_PATH.unshift(path) }
167
+ requires.each{ |path| require(path) }
168
+
169
+ suite = Lemon::Test::Suite.new(test_files, :cover=>true, :cover_all=>true)
170
+ cover = Lemon::Coverage.new(suite, namespaces, :public=>public_only)
171
+ #cover = Lemon::Coverage.new([], namespaces, :public=>public_only?, :uncovered=>uncovered)
172
+
173
+ if uncovered
174
+ puts cover.generate_uncovered #(output)
175
+ else
176
+ puts cover.generate #(output)
177
+ end
178
+
179
+ end
180
+
19
181
  end
20
182
 
21
183
  end
22
- end
184
+