Class: Tina4::Test
- Inherits:
-
Object
- Object
- Tina4::Test
- Defined in:
- lib/tina4/test.rb
Overview
Tina4 xUnit-style test base class — class-based test suites with HTTP helpers and positional assertions. Zero external dependencies.
Documentation chapter 18 has long described:
class UserApiTest < Tina4::Test
def test_health
resp = get("/health")
assert_equal_value(resp.status, 200)
end
end
Until 3.13.0 this class did not exist — examples crashed with “uninitialized constant Tina4::Test”. Ruby parity of the Python ‘tina4_python.test.Test` and PHP `Tina4Test` classes.
The class has a built-in runner (no Minitest/RSpec required):
results = Tina4::Test.run_all # discovers all subclasses
# => { passed: 12, failed: 0, errors: 0, details: [...] }
Or run a single suite class:
UserApiTest.run!
HTTP helpers (get/post/put/patch/delete) delegate to TestClient. Positional assertions match the Python (actual, expected, message) shape used throughout the cross-framework docs.
Class Attribute Summary collapse
-
.subclasses ⇒ Object
readonly
Returns the value of attribute subclasses.
Class Method Summary collapse
- .inherited(subclass) ⇒ Object
-
.run! ⇒ Object
Run every test method (‘test_*`) on the calling subclass.
-
.run_all(quiet: false) ⇒ Object
Discover and run every Tina4::Test subclass.
Instance Method Summary collapse
-
#assert_equal_value(actual, expected, message = nil) ⇒ Object
── Positional assertions — (actual, expected, message) shape ─────.
- #assert_false(value, message = nil) ⇒ Object
- #assert_nil_value(value, message = nil) ⇒ Object
- #assert_not_equal_value(actual, expected, message = nil) ⇒ Object
- #assert_not_nil_value(value, message = nil) ⇒ Object
- #assert_raises(expected_class, message = nil) ⇒ Object
- #assert_true(value, message = nil) ⇒ Object
- #delete(path, headers: nil) ⇒ Object
- #get(path, headers: nil) ⇒ Object
- #patch(path, json: nil, body: nil, headers: nil) ⇒ Object
- #post(path, json: nil, body: nil, headers: nil) ⇒ Object
- #put(path, json: nil, body: nil, headers: nil) ⇒ Object
-
#set_up ⇒ Object
── Lifecycle hooks ────────────────────────────────────────────── snake_case Tina4 idiom; override in subclasses.
- #tear_down ⇒ Object
-
#test_client ⇒ Object
── HTTP test client (lazy) ───────────────────────────────────────.
Class Attribute Details
.subclasses ⇒ Object (readonly)
Returns the value of attribute subclasses.
42 43 44 |
# File 'lib/tina4/test.rb', line 42 def subclasses @subclasses end |
Class Method Details
.inherited(subclass) ⇒ Object
44 45 46 47 |
# File 'lib/tina4/test.rb', line 44 def inherited(subclass) super Test.subclasses << subclass end |
.run! ⇒ Object
Run every test method (‘test_*`) on the calling subclass. Returns a hash with passed/failed/errors counts and per-test details.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/tina4/test.rb', line 51 def run! instance_methods(false).grep(/\Atest_/).sort.each_with_object( { passed: 0, failed: 0, errors: 0, details: [] } ) do |method, results| suite = new begin suite.send(:set_up) suite.send(method) suite.send(:tear_down) results[:passed] += 1 results[:details] << { suite: name, test: method, status: "passed" } rescue AssertionError => e results[:failed] += 1 results[:details] << { suite: name, test: method, status: "failed", message: e. } rescue StandardError => e results[:errors] += 1 results[:details] << { suite: name, test: method, status: "error", message: "#{e.class}: #{e.}" } end end end |
.run_all(quiet: false) ⇒ Object
Discover and run every Tina4::Test subclass.
73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/tina4/test.rb', line 73 def run_all(quiet: false) results = { passed: 0, failed: 0, errors: 0, details: [] } Test.subclasses.each do |klass| out = klass.run! results[:passed] += out[:passed] results[:failed] += out[:failed] results[:errors] += out[:errors] results[:details].concat(out[:details]) end unless quiet puts "Tina4 Test results: #{results[:passed]} passed, #{results[:failed]} failed, #{results[:errors]} errors" end results end |
Instance Method Details
#assert_equal_value(actual, expected, message = nil) ⇒ Object
── Positional assertions — (actual, expected, message) shape ─────
126 127 128 129 130 |
# File 'lib/tina4/test.rb', line 126 def assert_equal_value(actual, expected, = nil) return if actual == expected raise AssertionError, || "Expected #{expected.inspect}, got #{actual.inspect}" end |
#assert_false(value, message = nil) ⇒ Object
144 145 146 147 148 |
# File 'lib/tina4/test.rb', line 144 def assert_false(value, = nil) return unless value raise AssertionError, || "Expected falsy, got #{value.inspect}" end |
#assert_nil_value(value, message = nil) ⇒ Object
150 151 152 153 154 |
# File 'lib/tina4/test.rb', line 150 def assert_nil_value(value, = nil) return if value.nil? raise AssertionError, || "Expected nil, got #{value.inspect}" end |
#assert_not_equal_value(actual, expected, message = nil) ⇒ Object
132 133 134 135 136 |
# File 'lib/tina4/test.rb', line 132 def assert_not_equal_value(actual, expected, = nil) return unless actual == expected raise AssertionError, || "Expected #{actual.inspect} != #{expected.inspect}, but they are equal" end |
#assert_not_nil_value(value, message = nil) ⇒ Object
156 157 158 159 160 |
# File 'lib/tina4/test.rb', line 156 def assert_not_nil_value(value, = nil) return unless value.nil? raise AssertionError, || "Expected non-nil, got nil" end |
#assert_raises(expected_class, message = nil) ⇒ Object
162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/tina4/test.rb', line 162 def assert_raises(expected_class, = nil) raise ArgumentError, "Block required" unless block_given? begin yield rescue StandardError => e return if e.is_a?(expected_class) raise AssertionError, || "Expected #{expected_class}, got #{e.class}: #{e.}" end raise AssertionError, || "Expected #{expected_class} to be raised, but nothing was" end |
#assert_true(value, message = nil) ⇒ Object
138 139 140 141 142 |
# File 'lib/tina4/test.rb', line 138 def assert_true(value, = nil) return if value raise AssertionError, || "Expected truthy, got #{value.inspect}" end |
#delete(path, headers: nil) ⇒ Object
120 121 122 |
# File 'lib/tina4/test.rb', line 120 def delete(path, headers: nil) test_client.delete(path, headers: headers) end |
#get(path, headers: nil) ⇒ Object
104 105 106 |
# File 'lib/tina4/test.rb', line 104 def get(path, headers: nil) test_client.get(path, headers: headers) end |
#patch(path, json: nil, body: nil, headers: nil) ⇒ Object
116 117 118 |
# File 'lib/tina4/test.rb', line 116 def patch(path, json: nil, body: nil, headers: nil) test_client.patch(path, json: json, body: body, headers: headers) end |
#post(path, json: nil, body: nil, headers: nil) ⇒ Object
108 109 110 |
# File 'lib/tina4/test.rb', line 108 def post(path, json: nil, body: nil, headers: nil) test_client.post(path, json: json, body: body, headers: headers) end |
#put(path, json: nil, body: nil, headers: nil) ⇒ Object
112 113 114 |
# File 'lib/tina4/test.rb', line 112 def put(path, json: nil, body: nil, headers: nil) test_client.put(path, json: json, body: body, headers: headers) end |
#set_up ⇒ Object
── Lifecycle hooks ──────────────────────────────────────────────snake_case Tina4 idiom; override in subclasses.
92 93 |
# File 'lib/tina4/test.rb', line 92 def set_up end |
#tear_down ⇒ Object
95 96 |
# File 'lib/tina4/test.rb', line 95 def tear_down end |
#test_client ⇒ Object
── HTTP test client (lazy) ───────────────────────────────────────
100 101 102 |
# File 'lib/tina4/test.rb', line 100 def test_client @test_client ||= Tina4::TestClient.new end |