test4requirements 0.1.0.alpha.2 → 0.1.0
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.
- data/examples/example_fail_pend_omit.rb +58 -0
- data/examples/example_small.rb +35 -0
- data/examples/example_test4requirements.rb +68 -61
- data/examples/example_test4requirements_shoulda.rb +63 -59
- data/examples/test4requirements.rb +11 -0
- data/lib/test4requirements.rb +106 -98
- data/lib/test4requirements/requirement.rb +56 -35
- data/lib/test4requirements/requirementlist.rb +111 -18
- data/lib/test4requirements/shoulda.rb +114 -77
- data/lib/test4requirements/testcase.rb +10 -12
- data/unittest/check_compatibility.rb +65 -65
- data/unittest/unittest_requirement.rb +28 -19
- data/unittest/unittest_requirementlist.rb +50 -34
- data/unittest/{unittest_requirementlist_overview.rb → unittest_requirementlist_with_tests.rb} +257 -199
- data/unittest/unittest_shoulda.rb +123 -123
- data/unittest/unittest_testcase.rb +4 -4
- metadata +21 -17
@@ -1,6 +1,5 @@
|
|
1
1
|
=begin rdoc
|
2
2
|
Define a requirement.
|
3
|
-
|
4
3
|
=end
|
5
4
|
module Test4requirements
|
6
5
|
class Requirement
|
@@ -8,19 +7,24 @@ module Test4requirements
|
|
8
7
|
OPTIONS = [
|
9
8
|
:description,
|
10
9
|
:reference,
|
10
|
+
:key, #optional, but must be identic with first parameter
|
11
11
|
]
|
12
12
|
=begin rdoc
|
13
13
|
Each requirement must include a key.
|
14
14
|
|
15
15
|
Optional values:
|
16
16
|
* description
|
17
|
-
* reference
|
17
|
+
* reference, e.g. 'Customer Requirement, Version 2011-08-02, page 12'
|
18
|
+
|
18
19
|
=end
|
19
20
|
def initialize( key, options = {} )
|
21
|
+
|
20
22
|
@key = key
|
21
23
|
options.keys.each{|key|
|
22
|
-
raise ArgumentError, "
|
24
|
+
raise ArgumentError, "#{self.class}.new: Option #{key} undefined" unless OPTIONS.include?(key)
|
23
25
|
}
|
26
|
+
raise ArgumentError, "#{self.class}.new: Key not explicit: #{key}" if options[:key] and options[:key] != key
|
27
|
+
|
24
28
|
@description = options[:description]
|
25
29
|
@reference = options[:reference]
|
26
30
|
|
@@ -36,8 +40,16 @@ Optional values:
|
|
36
40
|
attr_reader :reference
|
37
41
|
#Logger. Defined by RequirementList#<<
|
38
42
|
attr_accessor :log
|
43
|
+
#Testcases of the requirement
|
44
|
+
attr_reader :tests
|
39
45
|
|
40
|
-
|
46
|
+
=begin rdoc
|
47
|
+
Assign a TestCase.
|
48
|
+
=end
|
49
|
+
def test=(loc)
|
50
|
+
@log.info("Test #{loc} assigned to requirement #{@key}") if @log and @log.info?
|
51
|
+
@tests[loc] = [] #Collects problems
|
52
|
+
end
|
41
53
|
=begin rdoc
|
42
54
|
Returns the result of a TestCase.
|
43
55
|
|
@@ -46,46 +58,38 @@ Returns the result of a TestCase.
|
|
46
58
|
* true: Succesfull tested
|
47
59
|
=end
|
48
60
|
def [](key)
|
49
|
-
@tests[key]
|
61
|
+
return nil unless @tests[key]
|
62
|
+
return @tests[key].uniq == [:ok]
|
50
63
|
end
|
51
|
-
|
52
64
|
=begin rdoc
|
53
|
-
|
65
|
+
Set a result for a test case.
|
54
66
|
=end
|
55
|
-
def
|
56
|
-
@
|
57
|
-
@tests[
|
58
|
-
end
|
59
|
-
|
60
|
-
=begin rdoc
|
61
|
-
Mark a test as successfull.
|
62
|
-
=end
|
63
|
-
def successfull_test(loc)
|
64
|
-
#fixme: Check if already defined?
|
65
|
-
#~ raise ArgumentError, "Successfull test #{loc} was never assigned" unless @tests.has_key?(loc)
|
66
|
-
@log.info("Test #{loc} successfull for to requirement #{@key}") if @log and @log.info?
|
67
|
-
@tests[loc] = true #Was successfull tested
|
67
|
+
def result(key, val)
|
68
|
+
@tests[key] ||= []
|
69
|
+
@tests[key] << val
|
68
70
|
end
|
71
|
+
|
69
72
|
=begin rdoc
|
70
73
|
Return false, if no test is defined.
|
71
74
|
Else you get the number of tests.
|
72
75
|
=end
|
73
|
-
def
|
76
|
+
def test_defined?()
|
74
77
|
return @tests.empty? ? false : @tests.size
|
75
78
|
end
|
76
79
|
=begin rdoc
|
77
80
|
Test, if the requirement was successfull.
|
78
81
|
|
79
82
|
If there is one test without success, the requirement is not successfull solved.
|
80
|
-
* nil: no test found
|
83
|
+
* nil: no test found or one test not executed
|
81
84
|
* false: At least one test not successfull
|
82
85
|
* true: Succesfull tested
|
83
86
|
=end
|
84
87
|
def successfull?()
|
85
|
-
return nil
|
88
|
+
return nil unless test_defined?
|
86
89
|
success = true
|
87
90
|
@tests.each{|key,result|
|
88
|
-
|
91
|
+
return nil if result.empty?
|
92
|
+
success = (success and (result - [:ok]).empty?)
|
89
93
|
}
|
90
94
|
return success
|
91
95
|
end
|
@@ -96,7 +100,10 @@ Return a list of tests with test result.
|
|
96
100
|
#single tests: Only key returned
|
97
101
|
#~ return @tests.keys if @tests.size == 1
|
98
102
|
res_ok = []
|
99
|
-
|
103
|
+
res_fail = []
|
104
|
+
res_pend = []
|
105
|
+
res_omit = []
|
106
|
+
res_error = [] #enclear erros status
|
100
107
|
@tests.each{|key, result|
|
101
108
|
#Convert key (for shoulda)
|
102
109
|
case key
|
@@ -106,20 +113,27 @@ Return a list of tests with test result.
|
|
106
113
|
key = "#{$2} (#{$1}/#{$3})"
|
107
114
|
end
|
108
115
|
|
109
|
-
if result
|
116
|
+
if result.include?(:failure)
|
117
|
+
res_fail << key
|
118
|
+
elsif result.include?(:pend)
|
119
|
+
res_pend << key
|
120
|
+
elsif result.include?(:omit)
|
121
|
+
res_omit << key
|
122
|
+
elsif result.include?(:ok)
|
110
123
|
res_ok << key
|
111
124
|
else
|
112
|
-
|
125
|
+
res_error << key
|
113
126
|
end
|
127
|
+
|
114
128
|
}
|
115
|
-
#return filled array, if other array is empty
|
116
|
-
return res_ok if res_err.empty?
|
117
|
-
return res_err if res_ok.empty?
|
118
129
|
|
119
|
-
[
|
120
|
-
|
121
|
-
|
122
|
-
|
130
|
+
res = []
|
131
|
+
res << "OK: #{res_ok.join(', ')}" unless res_ok.empty?
|
132
|
+
res << "Failure: #{res_fail.join(', ')}" unless res_fail.empty?
|
133
|
+
res << "Pending: #{res_pend.join(', ')}" unless res_pend.empty?
|
134
|
+
res << "Omission: #{res_omit.join(', ')}" unless res_omit.empty?
|
135
|
+
res << "Error: #{res_omit.join(', ')}" unless res_error.empty?
|
136
|
+
res
|
123
137
|
end
|
124
138
|
|
125
139
|
def to_s()
|
@@ -129,4 +143,11 @@ Return a list of tests with test result.
|
|
129
143
|
#~ "<Requirement #{key} #{@tests}>"
|
130
144
|
#~ end
|
131
145
|
end
|
132
|
-
end #module Test4requirements
|
146
|
+
end #module Test4requirements
|
147
|
+
|
148
|
+
__END__
|
149
|
+
req = Test4requirements::Requirement.new(1)
|
150
|
+
req.test='loc'
|
151
|
+
req.result('loc',:ok)
|
152
|
+
p req.test_defined?
|
153
|
+
p req.successfull?
|
@@ -15,14 +15,42 @@ This class can be used in Test::Unit::TestCase#assign_requirement.
|
|
15
15
|
=begin rdoc
|
16
16
|
Define a list of requirements.
|
17
17
|
|
18
|
-
Parameters
|
18
|
+
Parameters:
|
19
|
+
* name
|
20
|
+
* list of requirement (keys)
|
21
|
+
* options
|
22
|
+
* :requirements
|
23
|
+
* :log Define a logger
|
24
|
+
|
25
|
+
The list of requirements will define the key of a new Test4requirements::Requirement,
|
26
|
+
unless it is already a Test4requirements::Requirement.
|
27
|
+
|
28
|
+
Examples:
|
29
|
+
RequirementList.new('Request_4711')
|
30
|
+
RequirementList.new('Request_4711', :req1, :req2 )
|
31
|
+
RequirementList.new('Request_4711', Reqirement.new(:req1), Reqirement.new(:req2) )
|
32
|
+
RequirementList.new('Request_4711',
|
33
|
+
:requirements => [ :req1, :req2]
|
34
|
+
)
|
35
|
+
RequirementList.new('Request_4711',
|
36
|
+
Reqirement.new(:req1), Reqirement.new(:req2),
|
37
|
+
:requirements => [ :req3, :req4]
|
38
|
+
)
|
39
|
+
|
19
40
|
=end
|
20
|
-
def initialize( *
|
41
|
+
def initialize( name, *args )
|
21
42
|
|
22
|
-
|
43
|
+
options = {
|
44
|
+
:log => Log4r::Logger.new('ReqL'),
|
45
|
+
:requirements => [],
|
46
|
+
}.merge( args.last.is_a?(Hash) ? args.pop : {} )
|
47
|
+
options[:requirements].concat(args)
|
48
|
+
|
49
|
+
@name = name
|
50
|
+
@log = options[:log]
|
23
51
|
|
24
52
|
@requirements = {}
|
25
|
-
|
53
|
+
options[:requirements].each{|req|
|
26
54
|
|
27
55
|
#Define a requirement.
|
28
56
|
if ! req.is_a?(Requirement)
|
@@ -31,7 +59,8 @@ Parameters will define the key of new Requirement, unless it is no Requirement.
|
|
31
59
|
|
32
60
|
self << req
|
33
61
|
}
|
34
|
-
|
62
|
+
@testsresults = []
|
63
|
+
|
35
64
|
#Yes, we need two at_exit.
|
36
65
|
#tests are done also at_exit. With double at_exit, we are after that.
|
37
66
|
#Maybe better to be added later.
|
@@ -42,8 +71,13 @@ Parameters will define the key of new Requirement, unless it is no Requirement.
|
|
42
71
|
}
|
43
72
|
@report_type = self.class.report_type_default # alternatives: nil, :stdout, :txt
|
44
73
|
end #initialize
|
74
|
+
#Name or ID of the requirement list.
|
75
|
+
attr_reader :name
|
45
76
|
#Logger
|
46
77
|
attr_reader :log
|
78
|
+
#List of related result objects Test::Unit::TestResult (one per suite, normally only 1)
|
79
|
+
attr_reader :testsresults
|
80
|
+
|
47
81
|
=begin rdoc
|
48
82
|
Add a new requirement.
|
49
83
|
=end
|
@@ -57,32 +91,67 @@ Add a new requirement.
|
|
57
91
|
@requirements[req.key] = req
|
58
92
|
end
|
59
93
|
=begin rdoc
|
94
|
+
Method to load requirements.
|
95
|
+
|
96
|
+
You can provide:
|
97
|
+
* an array of hashes with requirement definition
|
98
|
+
* a hash with key and requirement definition
|
99
|
+
|
100
|
+
The requirement definition can contain the options of Test4requirements::Requirement.
|
101
|
+
|
102
|
+
You may use yaml to define your requirments:
|
103
|
+
req = RequirementList.new('Requirementlist')
|
104
|
+
req.load( YAML.load( <<yaml
|
105
|
+
req1:
|
106
|
+
description: 'What is required',
|
107
|
+
reference: 'Customer Requirement, Version 2011-08-02, page 12'
|
108
|
+
req2:
|
109
|
+
description: 'What is required',
|
110
|
+
reference: 'Customer Requirement, Version 2011-08-02, page 13'
|
111
|
+
yaml
|
112
|
+
))
|
113
|
+
=end
|
114
|
+
def load( data )
|
115
|
+
|
116
|
+
if data.is_a?(Hash)
|
117
|
+
#build array
|
118
|
+
datalist = []
|
119
|
+
data.each{|key,value| datalist << value.merge(:key => key )}
|
120
|
+
else
|
121
|
+
datalist = data
|
122
|
+
end
|
123
|
+
datalist.each{|req|
|
124
|
+
self << Requirement.new( req[:key], req )
|
125
|
+
}
|
126
|
+
end
|
127
|
+
=begin rdoc
|
60
128
|
Returns Requirement
|
61
129
|
=end
|
62
130
|
def [](key)
|
63
131
|
@requirements[key]
|
64
132
|
end
|
65
133
|
=begin rdoc
|
134
|
+
Loop on all requirements.
|
135
|
+
|
136
|
+
Returns list of all requirements.
|
137
|
+
=end
|
138
|
+
def each()
|
139
|
+
@requirements.each{|key,req| yield req} if block_given?
|
140
|
+
@requirements.values
|
141
|
+
end
|
142
|
+
=begin rdoc
|
66
143
|
Assign a testcase to an requirement.
|
67
144
|
|
68
145
|
Requires:
|
69
146
|
* Requirement key
|
70
147
|
* testcase (Class#methodname)
|
71
148
|
=end
|
72
|
-
def assign_test(req, testcase)
|
149
|
+
def assign_test(req, testcase, result)
|
73
150
|
raise ArgumentError unless @requirements[req]
|
151
|
+
#~ raise ArgumentError, "result is no Test::Unit::TestResult but #{result.inspect}" unless result.is_a?(Test::Unit::TestResult)
|
74
152
|
@requirements[req].test= testcase
|
75
|
-
|
76
|
-
|
77
|
-
Report successfull test to the requirement.
|
78
|
-
|
79
|
-
This requires a previous assignment with #assign_test.
|
80
|
-
=end
|
81
|
-
def test_successfull(loc)
|
82
|
-
#~ raise ArgumentError unless @requirements[req]
|
83
|
-
@requirements.each{|key,req|
|
84
|
-
req.successfull_test(loc) unless req[loc].nil?
|
85
|
-
}
|
153
|
+
#Assign the related result object Test::Unit::TestResult
|
154
|
+
@testsresults << result unless @testsresults.include?(result)
|
86
155
|
end
|
87
156
|
=begin rdoc
|
88
157
|
Defines, how and if an overview of the requirements are given.
|
@@ -99,6 +168,28 @@ Used in #overview. More details see there.
|
|
99
168
|
end
|
100
169
|
end
|
101
170
|
=begin rdoc
|
171
|
+
=end
|
172
|
+
def analyse_testresults()
|
173
|
+
@testsresults.each{|result|
|
174
|
+
result.faults.each{|fault|
|
175
|
+
self.each{|req|
|
176
|
+
if ! req[fault.test_name].nil?
|
177
|
+
@log.debug("Set result #{fault} to #{req}") if @log.info?
|
178
|
+
case fault
|
179
|
+
when Test::Unit::Failure; req.result(fault.test_name, :failure)
|
180
|
+
when Test::Unit::Pending; req.result(fault.test_name, :pend)
|
181
|
+
when Test::Unit::Omission; req.result(fault.test_name, :omit)
|
182
|
+
else
|
183
|
+
@log.error("unknown fault-type #{fault.inspect}") if @log.error?
|
184
|
+
req.set_result(fault.test_name, :error)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
}
|
188
|
+
|
189
|
+
}
|
190
|
+
}
|
191
|
+
end
|
192
|
+
=begin rdoc
|
102
193
|
Give an overview.
|
103
194
|
|
104
195
|
Returns a hash with test results for the requirements.
|
@@ -113,6 +204,8 @@ The parameter defines alternative report types:
|
|
113
204
|
=end
|
114
205
|
def overview(report_type = @report_type )
|
115
206
|
|
207
|
+
analyse_testresults()
|
208
|
+
|
116
209
|
txt = []
|
117
210
|
hash = {}
|
118
211
|
|
@@ -120,7 +213,7 @@ The parameter defines alternative report types:
|
|
120
213
|
if req.successfull?
|
121
214
|
txt << "Requirement #{key} was successfull tested (#{req.testresults.join(', ')})"
|
122
215
|
hash[key] = true
|
123
|
-
elsif req.
|
216
|
+
elsif req.test_defined?
|
124
217
|
txt << "Requirement #{key} was unsuccessfull tested (#{req.testresults.join(', ')})"
|
125
218
|
hash[key] = false
|
126
219
|
else
|
@@ -1,77 +1,114 @@
|
|
1
|
-
=begin rdoc
|
2
|
-
Support of shoulda.
|
3
|
-
|
4
|
-
Details on usage see examples/example_test4requirements_shoulda.rb
|
5
|
-
|
6
|
-
Fixmes:
|
7
|
-
* should_not is not supported yet
|
8
|
-
=end
|
9
|
-
|
10
|
-
require_relative '../test4requirements'
|
11
|
-
require 'shoulda' #tested with shoulda 2.11.3
|
12
|
-
|
13
|
-
#
|
14
|
-
module
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
=
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
1
|
+
=begin rdoc
|
2
|
+
Support of shoulda.
|
3
|
+
|
4
|
+
Details on usage see examples/example_test4requirements_shoulda.rb
|
5
|
+
|
6
|
+
Fixmes:
|
7
|
+
* should_not is not supported yet
|
8
|
+
=end
|
9
|
+
|
10
|
+
require_relative '../test4requirements'
|
11
|
+
require 'shoulda' #tested with shoulda 2.11.3
|
12
|
+
|
13
|
+
#
|
14
|
+
module Test4requirements
|
15
|
+
=begin rdoc
|
16
|
+
Dummy class TestResults for use with Shoulda
|
17
|
+
=end
|
18
|
+
class TestResults
|
19
|
+
def initialize()
|
20
|
+
@faults = []
|
21
|
+
end
|
22
|
+
attr_reader :faults
|
23
|
+
end #class TestResults
|
24
|
+
end #module Test4requirements
|
25
|
+
|
26
|
+
module Test
|
27
|
+
module Unit
|
28
|
+
class TestCase
|
29
|
+
class << self
|
30
|
+
#remember original definition.
|
31
|
+
alias :should_old :should
|
32
|
+
=begin rdoc
|
33
|
+
Extend #should to support assignment to requirement.
|
34
|
+
|
35
|
+
Usage:
|
36
|
+
should 'fullfill request 1', requirement: :req1 do
|
37
|
+
assert_equal(2,1+1)
|
38
|
+
end
|
39
|
+
=end
|
40
|
+
def should(name_or_matcher, options = {}, &blk)
|
41
|
+
if ! self.name
|
42
|
+
raise RuntimeError, "Shoulda not defined for anonymous classes"
|
43
|
+
end
|
44
|
+
if options[:requirement]
|
45
|
+
#testmethodname must fit self.name of the later test (TestCase#run_test)
|
46
|
+
testmethodname = 'test: '
|
47
|
+
testmethodname << self.name.gsub(/Test/, "")
|
48
|
+
testmethodname << ' should '
|
49
|
+
testmethodname << name_or_matcher
|
50
|
+
testmethodname << '. '
|
51
|
+
testmethodname << "(#{self.name})"
|
52
|
+
raise RuntimeError, "No requirements defined for #{self}" unless get_requirements
|
53
|
+
get_requirements.assign_test(options[:requirement], testmethodname, Test4requirements::TestResults.new)
|
54
|
+
end
|
55
|
+
should_old(name_or_matcher, options = {}, &blk)
|
56
|
+
end #should
|
57
|
+
end #eigenclass TestCase
|
58
|
+
end #class TestCase
|
59
|
+
end #module Unit
|
60
|
+
end #module Test
|
61
|
+
|
62
|
+
module Shoulda
|
63
|
+
class Context
|
64
|
+
#remember original definition.
|
65
|
+
alias :should_old :should
|
66
|
+
=begin rdoc
|
67
|
+
Extend #should inside a context to support assignment to requirement.
|
68
|
+
|
69
|
+
Usage:
|
70
|
+
should 'fullfill request 1', requirement: :req1 do
|
71
|
+
assert_equal(2,1+1)
|
72
|
+
end
|
73
|
+
=end
|
74
|
+
def should(name_or_matcher, options = {}, &blk)
|
75
|
+
if options[:requirement]
|
76
|
+
#testmethodname must fit self.name of the later test (TestCase#run_test)
|
77
|
+
testmethodname = 'test: '
|
78
|
+
testmethodname << self.name
|
79
|
+
testmethodname << ' should '
|
80
|
+
testmethodname << name_or_matcher
|
81
|
+
testmethodname << '. '
|
82
|
+
testmethodname << "(#{self.parent.name})"
|
83
|
+
raise RuntimeError, "No requirements defined for #{self}" unless get_requirements
|
84
|
+
get_requirements.assign_test(options[:requirement], testmethodname, Test4requirements::TestResults.new )
|
85
|
+
end
|
86
|
+
should_old(name_or_matcher, options = {}, &blk)
|
87
|
+
end #should
|
88
|
+
end# class Context
|
89
|
+
end #Shoulda
|
90
|
+
|
91
|
+
__END__
|
92
|
+
|
93
|
+
include Test4requirements
|
94
|
+
$reqs = RequirementList.new(:reqId, :req1,:req2,:req3)
|
95
|
+
class Testcase < Test::Unit::TestCase
|
96
|
+
#Set class name. Normally class name.
|
97
|
+
def self.name;'Test_ShouldaTest';end
|
98
|
+
|
99
|
+
self.requirements= $reqs
|
100
|
+
#Add requirement as parameter of should
|
101
|
+
should 'request_1', requirement: :req1 do
|
102
|
+
assert_equal(2,1+1)
|
103
|
+
end
|
104
|
+
|
105
|
+
#add requirement via requirement command
|
106
|
+
should 'request_2' do
|
107
|
+
assign_requirement(:req2) #this test is testing requirement 1
|
108
|
+
assert_equal(3,1+1)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
#~ suite = @testcase.suite #run tests
|
113
|
+
#~ Test::Unit::UI::Console::TestRunner.run(suite, :output => IO_Catcher)
|
114
|
+
p $reqs.overview
|