fas_test 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,19 @@
1
+ Auto-discovers test classes in the working directory and runs the tests with
2
+ basically no boot up time and no configuration. It doesn't matter how you
3
+ structure your project, instead, simple naming conventions are used:
4
+
5
+ - All test files should be named *_tests.rb
6
+ - All test methods should be named test__*
7
+
8
+ Other things you need to know:
9
+
10
+ - All test classes should inherit FasTest::TestClass
11
+ - Your test class can define "setup" and/or "teardown" methods. They do what
12
+ it sounds like they do.
13
+
14
+ Take a look in the test folder to see an example of how the library is used.
15
+ (fas_test is used to test itself).
16
+
17
+ To actually run your tests just invoke fastest.rb from a command line. It will
18
+ automatically recursively discover all of your test classes within the working
19
+ directory and run there tests.
data/bin/fastest.rb ADDED
@@ -0,0 +1,5 @@
1
+ require 'lib/fas_test'
2
+
3
+ test_runner = FasTest::TestRunner.new
4
+ test_runner.run_tests_in_folder(".")
5
+ test_runner.print_summary
data/lib/fas_test.rb ADDED
@@ -0,0 +1,197 @@
1
+ module FasTest
2
+
3
+ # Used to discover tests and actually run them. Normally this class will be
4
+ # used by the command line client.
5
+ class TestRunner
6
+
7
+ attr_reader :test_results
8
+
9
+ def initialize(verbose = false)
10
+ @verbose = verbose
11
+ @assertion_count = 0
12
+ @test_results = {}
13
+ end
14
+
15
+ def run_tests_in_class(test_class)
16
+ test_instance = init_test_instance(test_class)
17
+ get_all_test_method_names(test_class).each do |test_method_name|
18
+ run_test(test_instance, test_method_name)
19
+ end
20
+ end
21
+
22
+ def init_test_instance(test_class)
23
+ test_instance = test_class.new
24
+ test_instance.runner = self
25
+ return test_instance
26
+ end
27
+
28
+ def increment_assert_count
29
+ @assertion_count += 1
30
+ end
31
+
32
+ def run_test(test_instance, test_method_name)
33
+ begin
34
+ status = TestStatuses::PASS
35
+ test_instance.setup
36
+ test_instance.needs_teardown = true
37
+ test_instance.send(test_method_name)
38
+ if @verbose
39
+ puts "Pass: #{test_instance.class.name}::#{test_method_name}"
40
+ end
41
+ rescue AssertionException => ex
42
+ status = TestStatuses::FAIL
43
+ try_teardown(test_instance)
44
+ puts "Fail: #{test_instance.class.name}::#{test_method_name}"
45
+ puts " -> #{ex.message}"
46
+ rescue Exception => ex
47
+ status = TestStatuses::CRASH
48
+ try_teardown(test_instance)
49
+ puts "Crash: #{test_instance.class.name}::#{test_method_name}"
50
+ puts " -> #{ex.class.name}: #{ex.message}"
51
+ pretty_print_stack_trace(ex)
52
+ rescue Object => obj
53
+ status = TestStatuses::CRASH
54
+ try_teardown(test_instance)
55
+ puts "Crash: #{test_instance.class.name}::#{test_method_name}"
56
+ puts " -> Raised non-exception: #{obj.to_s}"
57
+ ensure
58
+ try_teardown(test_instance)
59
+ record_test_result(test_instance, test_method_name, status)
60
+ end
61
+ end
62
+
63
+ def record_test_result(test_instance, test_method_name, status)
64
+ test_class = test_instance.class
65
+ key = "#{test_class.name}::#{test_method_name}"
66
+ @test_results[key] = TestResult.new(test_class, test_method_name, status)
67
+ end
68
+
69
+ def try_teardown(test_instance)
70
+ if test_instance.needs_teardown
71
+ begin
72
+ test_instance.teardown
73
+ ensure
74
+ test_instance.needs_teardown = false
75
+ end
76
+ end
77
+ end
78
+
79
+ def pretty_print_stack_trace(exception)
80
+ exception.backtrace.each { |trace| puts " #{trace}"}
81
+ end
82
+
83
+ def run_tests_in_folder(path)
84
+ load_test_files(path)
85
+ find_test_classes.each do |test_class|
86
+ run_tests_in_class(test_class)
87
+ end
88
+ end
89
+
90
+ def load_test_files(path)
91
+ Dir[File.join(path, '/**/*_tests.rb')].each { |file_name| load file_name }
92
+ end
93
+
94
+ def get_all_test_method_names(test_class)
95
+ test_class.instance_methods.find_all { |m| m.start_with?('test__') }
96
+ end
97
+
98
+ def find_test_classes
99
+ classes = []
100
+ Module.constants.each do |constant|
101
+ if constant.end_with? "Tests"
102
+ classes << eval(constant)
103
+ end
104
+ end
105
+ return classes
106
+ end
107
+
108
+ def get_constant_type(construct)
109
+ construct_class = construct.class
110
+ if construct_class == Class
111
+ return ConstantTypes::CLASS
112
+ elsif construct_class == Module
113
+ return ConstantTypes::MODULE
114
+ else
115
+ return ConstantTypes::OTHER
116
+ end
117
+ end
118
+
119
+ def class_inherits_parent?(child_class, parent_class)
120
+ child_class.ancestors.any? { |ancestor| ancestor == parent_class }
121
+ end
122
+
123
+ def print_summary
124
+ pass_count = @test_results.values.find_all { |r| r.status == TestStatuses::PASS }.length
125
+ fail_count = @test_results.length - pass_count
126
+ puts "#{pass_count} passed; #{fail_count} failed; #{@assertion_count} assertions"
127
+ end
128
+
129
+ end
130
+
131
+ # Types that a ruby constant can refer to
132
+ class ConstantTypes
133
+ CLASS = 1
134
+ MODULE = 2
135
+ OTHER = 3
136
+ end
137
+
138
+ # Base class for all test suites
139
+ class TestClass
140
+
141
+ attr_writer :runner
142
+ attr_accessor :needs_teardown
143
+
144
+ def setup
145
+ end
146
+
147
+ def teardown
148
+ end
149
+
150
+ def assert_true(expression, msg = "<no msg given>")
151
+ @runner.increment_assert_count
152
+ if expression != true
153
+ raise AssertionException, "expected true but got #{expression.to_s}"
154
+ end
155
+ end
156
+
157
+ def assert_equal(a, b, msg = "<no msg given>")
158
+ @runner.increment_assert_count
159
+ if a != b
160
+ raise AssertionException, "#{msg} | expected '#{a}' but got '#{b}'"
161
+ end
162
+ end
163
+
164
+ def fail(msg)
165
+ raise AssertionException, msg
166
+ end
167
+
168
+ end
169
+
170
+ # Represents the state of a finished test
171
+ class TestResult
172
+
173
+ attr_reader :test_class
174
+ attr_reader :method_name
175
+ attr_reader :status
176
+
177
+ def initialize(test_class, method_name, status)
178
+ @test_class = test_class
179
+ @method_name = method_name
180
+ @status = status
181
+ end
182
+
183
+ end
184
+
185
+ # Exception thrown when an assertion in a test fails
186
+ class AssertionException < Exception
187
+ end
188
+
189
+ # Enum of test result states
190
+ class TestStatuses
191
+ PASS = 1
192
+ FAIL = 2
193
+ CRASH = 3
194
+ end
195
+
196
+ end
197
+
@@ -0,0 +1,71 @@
1
+ require 'stringio'
2
+ require 'lib/fas_test'
3
+
4
+ class FasTestTests < FasTest::TestClass
5
+
6
+ def setup
7
+ $stdout = StringIO.new
8
+ end
9
+
10
+ def teardown
11
+ $stdout = STDOUT
12
+ end
13
+
14
+ def test__redirect_io
15
+ $stdout = StringIO.new
16
+ puts 'hello?'
17
+ assert_equal "hello?\n", $stdout.string
18
+ end
19
+
20
+ def test__run_tests_in_class__results_are_valid
21
+ runner = FasTest::TestRunner.new
22
+ runner.run_tests_in_class(FasTestTestClassTests)
23
+
24
+ assert_equal(5, runner.test_results.length, "wrong number of tests")
25
+
26
+ assert_equal(
27
+ FasTest::TestStatuses::PASS,
28
+ runner.test_results['FasTestTests::FasTestTestClassTests::test__pass1'].status)
29
+
30
+ assert_equal(
31
+ FasTest::TestStatuses::FAIL,
32
+ runner.test_results['FasTestTests::FasTestTestClassTests::test__fail1'].status)
33
+
34
+ assert_equal(
35
+ FasTest::TestStatuses::CRASH,
36
+ runner.test_results['FasTestTests::FasTestTestClassTests::test__crash1'].status)
37
+
38
+ assert_equal(
39
+ FasTest::TestStatuses::FAIL,
40
+ runner.test_results['FasTestTests::FasTestTestClassTests::test__assert_true_with_false'].status)
41
+
42
+ assert_equal(
43
+ FasTest::TestStatuses::PASS,
44
+ runner.test_results['FasTestTests::FasTestTestClassTests::test__asert_true_with_true'].status)
45
+ end
46
+
47
+ class FasTestTestClassTests < FasTest::TestClass
48
+
49
+ def test__pass1
50
+ end
51
+
52
+ def test__fail1
53
+ fail("this is an expected fail")
54
+ end
55
+
56
+ def test__crash1
57
+ i.am.calling.come.methods.that.dont.exist.so.it.should.crash
58
+ end
59
+
60
+ def test__assert_true_with_false
61
+ assert_true(false)
62
+ end
63
+
64
+ def test__asert_true_with_true
65
+ assert_true(true)
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fas_test
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Graeme Hill
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-02-24 00:00:00 -08:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: "Auto-discovers test classes in the working directory and runs the tests with\n\
23
+ basically no boot up time and no configuration. It doesn't matter how you\n\
24
+ structure your project, instead, simple naming conventions are used:\n\n - All test files should be named *_tests.rb\n - All test methods should be named test__*\n\n\
25
+ Other things you need to know:\n\n - All test classes should inherit FasTest::TestClass\n - Your test class can define \"setup\" and/or \"teardown\" methods. They do what\n it sounds like they do.\n\n\
26
+ Take a look in the test folder to see an example of how the library is used.\n\
27
+ (fas_test is used to test itself).\n\n\
28
+ To actually run your tests just invoke fastest.rb from a command line. It will\n\
29
+ automatically recursively discover all of your test classes within the working\n\
30
+ directory and run there tests. "
31
+ email: graemekh@gmail.com
32
+ executables: []
33
+
34
+ extensions: []
35
+
36
+ extra_rdoc_files:
37
+ - README
38
+ files:
39
+ - README
40
+ - bin/fastest.rb
41
+ - lib/fas_test.rb
42
+ - test/fas_test_tests.rb
43
+ has_rdoc: true
44
+ homepage: http://graemehill.ca
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options: []
49
+
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.5.2
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: A simple automated testing framework designed to be fast and easy to use.
77
+ test_files:
78
+ - test/fas_test_tests.rb