test4requirements 0.1.0.alpha.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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