test4requirements 0.1.0.alpha.2

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.
@@ -0,0 +1,62 @@
1
+ =begin rdoc
2
+ Some examples, how you can use test4requirements in your test.
3
+
4
+ Expectes Testresults:
5
+ req1 successfull
6
+ req2 tested, but without success
7
+ req3 no test
8
+ req4 successfull
9
+ =end
10
+ gem 'test-unit'#, '= 2.1.1'
11
+
12
+ $:.unshift('../lib')
13
+ require 'test4requirements.rb'
14
+
15
+ $req = Test4requirements::RequirementList.new(:req1,:req2,:req3, :req4)
16
+ #~ $req.log.outputters << Log4r::StdoutOutputter.new('stdout')
17
+ #Define a user defined action after test execution.
18
+ $req.do_after_tests{|reqlist|
19
+ puts reqlist.overview(nil)
20
+ }
21
+
22
+ =begin rdoc
23
+ Example code
24
+ =end
25
+ module Examples
26
+ =begin rdoc
27
+ Test requirements 1 and 2.
28
+ =end
29
+ class Test_requirement_1_2 < Test::Unit::TestCase
30
+ #Following requirements exist, and must be tested sucessfull
31
+ requirements $req
32
+
33
+ #Test requirement 1.
34
+ def test_1()
35
+ assign_requirement(:req1) #this test is testing requirement 1
36
+ assert_equal(2,1+1)
37
+ end
38
+ #Test requirement 2.
39
+ def test_2()
40
+ assign_requirement(:req2)
41
+ assert_equal(3,1+1)
42
+ end
43
+ #Test requirement 3, but without assignment to a requirement
44
+ def test_3()
45
+ #no assignment to requirement 3
46
+ pend 'pend'
47
+ end
48
+ end
49
+
50
+ =begin rdoc
51
+ Test requirement 4.
52
+ =end
53
+ class Test_requirement_4 < Test::Unit::TestCase
54
+ #Following requirements exist, and must be tested sucessfull
55
+ requirements $req
56
+ #Test requirement 4.
57
+ def test_4()
58
+ assign_requirement(:req4) #this test is testing requirement 4
59
+ assert_equal(2,1+1)
60
+ end
61
+ end
62
+ end #module Examples
@@ -0,0 +1,60 @@
1
+ =begin rdoc
2
+ Example code
3
+ =end
4
+
5
+ $:.unshift('../lib')
6
+ gem 'test-unit'#, '= 2.1.1'
7
+
8
+ require 'test4requirements'
9
+ require 'test4requirements/shoulda'
10
+ #~ require 'shoulda'
11
+
12
+ $req = Test4requirements::RequirementList.new(:req1,:req2,:req3, :req4, :req5)
13
+ #~ $req.log.outputters << Log4r::StdoutOutputter.new('stdout')
14
+
15
+ =begin rdoc
16
+ Example code
17
+ =end
18
+ module Examples
19
+ =begin rdoc
20
+ Some examples, how you can use test4requirements with shoulda.
21
+
22
+ Expected result:
23
+
24
+ Requirement req1 was successfull tested (fullfill request 1 (req. of customer X/Examples::Test_with_shoulda))
25
+ Requirement req2 was unsuccessfull tested (fullfill request 2 (req. of customer X/Examples::Test_with_shoulda))
26
+ Requirement req3 was successfull tested (request_3 (Examples::_with_shoulda/Examples::Test_with_shoulda))
27
+ Requirement req4 was successfull tested (request_4 (Examples::_with_shoulda/Examples::Test_with_shoulda))
28
+ Requirement req5 was not tested
29
+ =end
30
+ class Test_with_shoulda < Test::Unit::TestCase
31
+ #Following requirements exist, and must be tested sucessfull
32
+ requirements $req
33
+
34
+ context 'req. of customer X' do
35
+ #Add requirement as parameter of should
36
+ should 'fullfill request 1', requirement: :req1 do
37
+ assert_equal(2,1+1)
38
+ end
39
+ #add requirement via requirement command
40
+ should 'fullfill request 2' do
41
+ assign_requirement(:req2) #this test is testing requirement 1
42
+ assert_equal(3,1+1)
43
+ end
44
+ end #context
45
+
46
+ #Examples outside a context
47
+
48
+ #Add requirement as parameter of should
49
+ should 'request_3', requirement: :req3 do
50
+ assert_equal(2,1+1)
51
+ end
52
+
53
+ #add requirement via requirement command
54
+ should 'request_4' do
55
+ assign_requirement(:req4) #this test is testing requirement 1
56
+ assert_equal(2,1+1)
57
+ end
58
+
59
+ end #MyTest_shoulda
60
+ end #module Examples
@@ -0,0 +1,98 @@
1
+ =begin rdoc
2
+ This gem is based on a
3
+ {question at stackoverflow}[http://stackoverflow.com/questions/6958586/are-there-any-good-ruby-testing-traceability-solutions]:
4
+
5
+ :: Are there any gems that'll allow me to implement traceability from my tests back to designs/requirements?
6
+
7
+ :: i.e.: I want to tag my tests with the name of the requirements they test, and then generate reports of requirements that aren't tested or have failing tests, etc.
8
+
9
+ :title:test4requirements Unit-Testing with assignment to requirements
10
+
11
+ =Usage
12
+ require 'test4requirements.rb'
13
+
14
+ ==Define RequirementList and Requirements
15
+ You must define your requirements and a RequirementList.
16
+
17
+ You can make it with simple keys and without description:
18
+ $req = Test4requirements::RequirementList.new(:req1,:req2,:req3, :req4)
19
+
20
+ You may set an outputter to a logger:
21
+ $req.log.outputters << Log4r::StdoutOutputter.new('stdout')
22
+
23
+
24
+ Or you can define an empty list and assign requirements
25
+ with description etc.
26
+ $req = Test4requirements::RequirementList.new()
27
+ $req << Test4requirements::Requirement.new(
28
+ description: 'What is required',
29
+ reference: 'Customer Requirement, Version 2011-08-02, page 12'
30
+ )
31
+
32
+ ==Define your test cases
33
+
34
+ With Test::Unit::TestCase.requirments you can assign a RequirementList to your tests.
35
+ class Test_requirement < Test::Unit::TestCase
36
+ #Following requirements exist, and must be tested sucessfull
37
+ requirements $req
38
+ # ...
39
+ end
40
+
41
+ A RequirementList can be assigned to multiply TestCase.
42
+
43
+ ==Assign tests to requirements
44
+ Tests can by assigned to a requirement with
45
+ Test::Unit::TestCase#assign_requirement.
46
+
47
+ #Test requirement 1.
48
+ def test_1()
49
+ assign_requirement(:req1) #this test is testing requirement 1
50
+ assert_equal(2,1+1)
51
+ end
52
+
53
+ ==Get the result
54
+
55
+ Unit-Test are executed at_exit. Your results are not available before the tests are ready.
56
+
57
+ There are three ways to get information.
58
+
59
+ ===Standard reporting
60
+
61
+ Like the Unit-Test results the requirement-result are written at the end
62
+ with Test4requirements::RequirementList#overview
63
+
64
+ You can influence the output with Test4requirements::RequirementList#report_type=
65
+
66
+ ===Logger
67
+ There is a logger. You have access to teh logger with Test4requirements::RequirementList#log.
68
+ You can define outputters to the logger, you may log in a file to get more informations.
69
+ You can log to STDOUT, but the logging will be mixed with the test output.
70
+
71
+ ===User defined actions
72
+ Each action must be done at the end of the script.
73
+ You may use Test4requirements::RequirementList#do_after_tests to define an
74
+ action at the end of the script.
75
+
76
+ =end
77
+
78
+ gem 'test-unit'
79
+ =begin
80
+ unittest 2.3.1:
81
+ Test::Unit::Assertions uses Encoding#ascii_compatible?
82
+ Is not defined in ruby 1.9.1 (at least my installation ;) )
83
+ =end
84
+ gem 'test-unit', '<= 2.1.1' if RUBY_VERSION == '1.9.1'
85
+ require 'test/unit'
86
+
87
+ module Test4requirements
88
+ VERSION = '0.1.0.alpha.2'
89
+ end
90
+ require 'log4r'
91
+ require_relative 'test4requirements/testcase'
92
+ require_relative 'test4requirements/requirement'
93
+ require_relative 'test4requirements/requirementlist'
94
+
95
+ #Not loaded by default.
96
+ #require_relative 'test4requirements/shoulda'
97
+
98
+
@@ -0,0 +1,132 @@
1
+ =begin rdoc
2
+ Define a requirement.
3
+
4
+ =end
5
+ module Test4requirements
6
+ class Requirement
7
+ #Valid options for Requirement#new
8
+ OPTIONS = [
9
+ :description,
10
+ :reference,
11
+ ]
12
+ =begin rdoc
13
+ Each requirement must include a key.
14
+
15
+ Optional values:
16
+ * description
17
+ * reference
18
+ =end
19
+ def initialize( key, options = {} )
20
+ @key = key
21
+ options.keys.each{|key|
22
+ raise ArgumentError, "Key #{key} undefined" unless OPTIONS.include?(key)
23
+ }
24
+ @description = options[:description]
25
+ @reference = options[:reference]
26
+
27
+ #TestCases. Key is TestCase name.
28
+ @tests = {}
29
+
30
+ end
31
+ #Key of the requirement
32
+ attr_reader :key
33
+ #Description of the requirement
34
+ attr_reader :description
35
+ #Reference, e.g. 'Page 47, Requirement document 2'
36
+ attr_reader :reference
37
+ #Logger. Defined by RequirementList#<<
38
+ attr_accessor :log
39
+
40
+
41
+ =begin rdoc
42
+ Returns the result of a TestCase.
43
+
44
+ * nil: no test found
45
+ * false: Not successfull
46
+ * true: Succesfull tested
47
+ =end
48
+ def [](key)
49
+ @tests[key]
50
+ end
51
+
52
+ =begin rdoc
53
+ Assign a TestCase.
54
+ =end
55
+ def test=(loc)
56
+ @log.info("Test #{loc} assigned to requirement #{@key}") if @log and @log.info?
57
+ @tests[loc] = false #Will be tested
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
68
+ end
69
+ =begin rdoc
70
+ Return false, if no test is defined.
71
+ Else you get the number of tests.
72
+ =end
73
+ def tested?()
74
+ return @tests.empty? ? false : @tests.size
75
+ end
76
+ =begin rdoc
77
+ Test, if the requirement was successfull.
78
+
79
+ If there is one test without success, the requirement is not successfull solved.
80
+ * nil: no test found
81
+ * false: At least one test not successfull
82
+ * true: Succesfull tested
83
+ =end
84
+ def successfull?()
85
+ return nil if @tests.empty?
86
+ success = true
87
+ @tests.each{|key,result|
88
+ success = (success and result)
89
+ }
90
+ return success
91
+ end
92
+ =begin rdoc
93
+ Return a list of tests with test result.
94
+ =end
95
+ def testresults()
96
+ #single tests: Only key returned
97
+ #~ return @tests.keys if @tests.size == 1
98
+ res_ok = []
99
+ res_err = []
100
+ @tests.each{|key, result|
101
+ #Convert key (for shoulda)
102
+ case key
103
+ when /^test: (.*) should (.*)\. \((.*)\)/
104
+ #old: test: _Shoulda should request_2. (Test_ShouldaTest)
105
+ #new: request_2 (_Shoulda/Test_ShouldaTest)
106
+ key = "#{$2} (#{$1}/#{$3})"
107
+ end
108
+
109
+ if result
110
+ res_ok << key
111
+ else
112
+ res_err << key
113
+ end
114
+ }
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
+
119
+ [
120
+ "OK: #{res_ok.join(', ')}",
121
+ "Failure: #{res_err.join(', ')}",
122
+ ]
123
+ end
124
+
125
+ def to_s()
126
+ "<Requirement #{key}>"
127
+ end
128
+ #~ def inspect()
129
+ #~ "<Requirement #{key} #{@tests}>"
130
+ #~ end
131
+ end
132
+ end #module Test4requirements
@@ -0,0 +1,163 @@
1
+ module Test4requirements
2
+ =begin rdoc
3
+ Define a list of requirements.
4
+
5
+ This class can be used in Test::Unit::TestCase#assign_requirement.
6
+ =end
7
+ class RequirementList
8
+ class << self
9
+ #alternatives: nil, :stdout, :txt
10
+ #fixme: check valid values. see #report_type=
11
+ attr_accessor :report_type_default
12
+ end
13
+ #Set default report type.
14
+ self.report_type_default = :stdout
15
+ =begin rdoc
16
+ Define a list of requirements.
17
+
18
+ Parameters will define the key of new Requirement, unless it is no Requirement.
19
+ =end
20
+ def initialize( *reqs )
21
+
22
+ @log = Log4r::Logger.new('ReqL')
23
+
24
+ @requirements = {}
25
+ reqs.each{|req|
26
+
27
+ #Define a requirement.
28
+ if ! req.is_a?(Requirement)
29
+ req = Requirement.new(req)
30
+ end
31
+
32
+ self << req
33
+ }
34
+
35
+ #Yes, we need two at_exit.
36
+ #tests are done also at_exit. With double at_exit, we are after that.
37
+ #Maybe better to be added later.
38
+ at_exit {
39
+ at_exit do
40
+ self.overview
41
+ end
42
+ }
43
+ @report_type = self.class.report_type_default # alternatives: nil, :stdout, :txt
44
+ end #initialize
45
+ #Logger
46
+ attr_reader :log
47
+ =begin rdoc
48
+ Add a new requirement.
49
+ =end
50
+ def <<(req)
51
+ raise ArgumentError, "Requirement is no Requiremnt but #{req.inspect}" unless req.is_a?(Requirement)
52
+ @log.info("Add requirement #{req.key}") if @log.info?
53
+ if @requirements[req.key]
54
+ raise ArgumentError, "Requirement #{req.key} defined twice"
55
+ end
56
+ req.log= Log4r::Logger.new("#{@log.name}::#{req.key}") unless req.log
57
+ @requirements[req.key] = req
58
+ end
59
+ =begin rdoc
60
+ Returns Requirement
61
+ =end
62
+ def [](key)
63
+ @requirements[key]
64
+ end
65
+ =begin rdoc
66
+ Assign a testcase to an requirement.
67
+
68
+ Requires:
69
+ * Requirement key
70
+ * testcase (Class#methodname)
71
+ =end
72
+ def assign_test(req, testcase)
73
+ raise ArgumentError unless @requirements[req]
74
+ @requirements[req].test= testcase
75
+ end
76
+ =begin rdoc
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
+ }
86
+ end
87
+ =begin rdoc
88
+ Defines, how and if an overview of the requirements are given.
89
+
90
+ Used in #overview. More details see there.
91
+ =end
92
+ def report_type=(key)
93
+ @log.info("Set report type #{key.inspect}") if @log.info?
94
+ case key
95
+ when :stdout, nil, :txt
96
+ @report_type = key
97
+ else
98
+ raise ArgumentError, "Unknown report type #{key} for #{self.class}"
99
+ end
100
+ end
101
+ =begin rdoc
102
+ Give an overview.
103
+
104
+ Returns a hash with test results for the requirements.
105
+ * true: Successfull tested
106
+ * false: Unsuccessfull tested
107
+ * nil: Not tested
108
+
109
+ The parameter defines alternative report types:
110
+ * nil: No output. Please evaluate the return value
111
+ * stdout: Result is written to stdout.
112
+ * :txt: The text of stdout as an Array
113
+ =end
114
+ def overview(report_type = @report_type )
115
+
116
+ txt = []
117
+ hash = {}
118
+
119
+ @requirements.each{|key, req|
120
+ if req.successfull?
121
+ txt << "Requirement #{key} was successfull tested (#{req.testresults.join(', ')})"
122
+ hash[key] = true
123
+ elsif req.tested?
124
+ txt << "Requirement #{key} was unsuccessfull tested (#{req.testresults.join(', ')})"
125
+ hash[key] = false
126
+ else
127
+ txt << "Requirement #{key} was not tested"
128
+ hash[key] = nil
129
+ end
130
+ }
131
+
132
+ case report_type
133
+ when :stdout
134
+ puts "Requirements overview:"
135
+ puts txt.join("\n")
136
+ when :txt
137
+ return txt
138
+ when nil
139
+ return hash
140
+ else
141
+ raise ArgumentError, "Undefined report type #{report_type}"
142
+ end
143
+
144
+ end #overview
145
+ =begin rdoc
146
+ Define an action at the end of the script (after the test).
147
+
148
+ This method can be used for user defined actions after test execution.
149
+ =end
150
+ def do_after_tests
151
+ raise ArgumentError, "do_after_tests: called without a block" unless block_given?
152
+ #Yes, we need two at_exit.
153
+ #The inner at_exit defines the action,
154
+ #the outer at_exit defines the action at the end.
155
+ #So it will be after the at_exit used by unit-test runner.
156
+ at_exit{
157
+ at_exit{
158
+ yield self
159
+ }
160
+ }
161
+ end #at_exit
162
+ end #RequirementList
163
+ end #module Test4requirements