smartest 0.1.0.alpha3 → 0.2.0.alpha1
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.
- checksums.yaml +4 -4
- data/DEVELOPMENT.md +46 -5
- data/README.md +132 -34
- data/SMARTEST_DESIGN.md +102 -10
- data/lib/smartest/dsl.rb +13 -6
- data/lib/smartest/errors.rb +16 -0
- data/lib/smartest/hook_contexts.rb +51 -0
- data/lib/smartest/init_generator.rb +4 -1
- data/lib/smartest/reporter.rb +18 -1
- data/lib/smartest/runner.rb +78 -14
- data/lib/smartest/suite.rb +34 -1
- data/lib/smartest/suite_run.rb +24 -0
- data/lib/smartest/test_case.rb +3 -2
- data/lib/smartest/test_run.rb +58 -0
- data/lib/smartest/version.rb +1 -1
- data/lib/smartest.rb +3 -0
- data/smartest/smartest_test.rb +309 -4
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ee5c1b7be401fa3dc4a8d88a25a241fc2b0bad486e8a3163a83c6c2340ae7c3c
|
|
4
|
+
data.tar.gz: f063204cd31bcd99b4654c26bb8591d566dcd424a2a312d9a7c9cbbea4292b01
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 18f117d867c86f47ff3d517729c0e7cbae4af5933b7432fa96ad30b1aea58a76b48e7ae4d3c129e72594598d19297751513d49501e5481c9ef07259a5350dafb
|
|
7
|
+
data.tar.gz: '085a5a10a7d5248d7888fd6267edae7c4dd88077f5b413d45385d4c05245b0eae771975ab67a50befc8ca14d8acb3d148d9718d94b431caf9800d2a2daa78627'
|
data/DEVELOPMENT.md
CHANGED
|
@@ -102,7 +102,8 @@ Responsibilities:
|
|
|
102
102
|
|
|
103
103
|
- test registry
|
|
104
104
|
- fixture class registry
|
|
105
|
-
-
|
|
105
|
+
- matcher registry
|
|
106
|
+
- `around_suite` hook registry
|
|
106
107
|
|
|
107
108
|
Example shape:
|
|
108
109
|
|
|
@@ -125,10 +126,14 @@ Required methods:
|
|
|
125
126
|
|
|
126
127
|
```ruby
|
|
127
128
|
test(name, **metadata, &block)
|
|
128
|
-
|
|
129
|
-
|
|
129
|
+
around_suite(&block)
|
|
130
|
+
around_test(&block)
|
|
130
131
|
```
|
|
131
132
|
|
|
133
|
+
`use_fixture(klass)` and `use_matcher(matcher_module)` are not top-level DSL
|
|
134
|
+
methods. They are available only from hook execution contexts: `around_suite`
|
|
135
|
+
and `around_test`.
|
|
136
|
+
|
|
132
137
|
Possible later methods:
|
|
133
138
|
|
|
134
139
|
```ruby
|
|
@@ -263,7 +268,10 @@ Responsibilities:
|
|
|
263
268
|
Example:
|
|
264
269
|
|
|
265
270
|
```ruby
|
|
266
|
-
|
|
271
|
+
around_suite do |suite|
|
|
272
|
+
use_fixture AppFixture
|
|
273
|
+
suite.run
|
|
274
|
+
end
|
|
267
275
|
```
|
|
268
276
|
|
|
269
277
|
should register `AppFixture`.
|
|
@@ -314,6 +322,7 @@ Runs tests.
|
|
|
314
322
|
Responsibilities:
|
|
315
323
|
|
|
316
324
|
- iterate over registered test cases
|
|
325
|
+
- run registered `around_suite` hooks around the suite body
|
|
317
326
|
- create a lazy suite-scoped `FixtureSet`
|
|
318
327
|
- create a fresh `ExecutionContext` per test
|
|
319
328
|
- create a fresh `FixtureSet` per test
|
|
@@ -324,6 +333,11 @@ Responsibilities:
|
|
|
324
333
|
- produce `TestResult`
|
|
325
334
|
- notify reporter
|
|
326
335
|
|
|
336
|
+
`around_suite` hooks receive a run target and must call `suite.run` exactly once.
|
|
337
|
+
Registered hooks compose in registration order, so the first hook is the
|
|
338
|
+
outermost wrapper. If a hook raises or does not call `suite.run`, the runner
|
|
339
|
+
reports a suite failure and exits with status `1`.
|
|
340
|
+
|
|
327
341
|
Pseudo-code:
|
|
328
342
|
|
|
329
343
|
```ruby
|
|
@@ -577,7 +591,7 @@ A practical approach:
|
|
|
577
591
|
|
|
578
592
|
- `Smartest::Fixture`
|
|
579
593
|
- `fixture :name do ... end`
|
|
580
|
-
- `use_fixture`
|
|
594
|
+
- `use_fixture` from a hook context
|
|
581
595
|
- test block keyword fixture resolution
|
|
582
596
|
|
|
583
597
|
### Phase 3: Fixture dependencies
|
|
@@ -620,6 +634,21 @@ A practical approach:
|
|
|
620
634
|
- generate a `smartest/test_helper.rb` that loads `smartest/fixtures/**/*.rb`
|
|
621
635
|
- exit code 0 on success, 1 on failure
|
|
622
636
|
|
|
637
|
+
### Phase 7: Suite hooks
|
|
638
|
+
|
|
639
|
+
- `around_suite do |suite| ... end`
|
|
640
|
+
- run hooks around the full suite body
|
|
641
|
+
- include suite fixture cleanup inside the wrapped body
|
|
642
|
+
- report hook failures as suite failures
|
|
643
|
+
|
|
644
|
+
### Phase 8: Test hooks
|
|
645
|
+
|
|
646
|
+
- `around_test do |test| ... end`
|
|
647
|
+
- snapshot file-local hooks when each test is registered
|
|
648
|
+
- run hooks around fixture setup, test body, and fixture cleanup
|
|
649
|
+
- expose `use_fixture` and `use_matcher` only inside hook contexts
|
|
650
|
+
- make `around_test` registered from `around_suite` suite-wide
|
|
651
|
+
|
|
623
652
|
## MVP API rules
|
|
624
653
|
|
|
625
654
|
Supported:
|
|
@@ -648,6 +677,18 @@ end
|
|
|
648
677
|
cleanup { ... }
|
|
649
678
|
```
|
|
650
679
|
|
|
680
|
+
```ruby
|
|
681
|
+
around_suite do |suite|
|
|
682
|
+
suite.run
|
|
683
|
+
end
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
```ruby
|
|
687
|
+
around_test do |test|
|
|
688
|
+
test.run
|
|
689
|
+
end
|
|
690
|
+
```
|
|
691
|
+
|
|
651
692
|
Not supported in MVP:
|
|
652
693
|
|
|
653
694
|
```ruby
|
data/README.md
CHANGED
|
@@ -173,9 +173,9 @@ be_nil
|
|
|
173
173
|
raise_error(ErrorClass)
|
|
174
174
|
```
|
|
175
175
|
|
|
176
|
-
Custom matcher modules can be registered
|
|
177
|
-
scaffold includes a `PredicateMatcher` custom
|
|
178
|
-
See [Matchers](documentation/docs/matchers.md).
|
|
176
|
+
Custom matcher modules can be registered from `around_suite` or `around_test`
|
|
177
|
+
with `use_matcher`. The generated scaffold includes a `PredicateMatcher` custom
|
|
178
|
+
matcher for `be_<predicate>` calls. See [Matchers](documentation/docs/matchers.md).
|
|
179
179
|
|
|
180
180
|
## Fixtures
|
|
181
181
|
|
|
@@ -192,10 +192,13 @@ class AppFixture < Smartest::Fixture
|
|
|
192
192
|
end
|
|
193
193
|
```
|
|
194
194
|
|
|
195
|
-
Register fixture classes from `smartest/test_helper.rb`:
|
|
195
|
+
Register fixture classes from `around_suite` in `smartest/test_helper.rb`:
|
|
196
196
|
|
|
197
197
|
```ruby
|
|
198
|
-
|
|
198
|
+
around_suite do |suite|
|
|
199
|
+
use_fixture AppFixture
|
|
200
|
+
suite.run
|
|
201
|
+
end
|
|
199
202
|
```
|
|
200
203
|
|
|
201
204
|
Tests request fixtures by keyword:
|
|
@@ -274,6 +277,100 @@ Suite fixtures are lazy: setup runs the first time a test requests the fixture,
|
|
|
274
277
|
and cleanup runs once after all tests finish. Test-scoped fixtures can depend on
|
|
275
278
|
suite fixtures, but suite fixtures cannot depend on test-scoped fixtures.
|
|
276
279
|
|
|
280
|
+
## Suite hooks
|
|
281
|
+
|
|
282
|
+
Use `around_suite` when the full test run must execute inside another block:
|
|
283
|
+
|
|
284
|
+
```ruby
|
|
285
|
+
around_suite do |suite|
|
|
286
|
+
Async do
|
|
287
|
+
suite.run
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
The hook receives a run target and must call `suite.run` exactly once. The block
|
|
293
|
+
wraps every test, test-scoped fixture setup and cleanup, suite fixture setup, and
|
|
294
|
+
suite fixture cleanup.
|
|
295
|
+
|
|
296
|
+
Fixture and matcher registrations made before `suite.run` are applied to that
|
|
297
|
+
run:
|
|
298
|
+
|
|
299
|
+
```ruby
|
|
300
|
+
around_suite do |suite|
|
|
301
|
+
use_fixture GlobalFixture
|
|
302
|
+
suite.run
|
|
303
|
+
end
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Multiple `around_suite` hooks run in registration order. The first hook is the
|
|
307
|
+
outermost wrapper:
|
|
308
|
+
|
|
309
|
+
```ruby
|
|
310
|
+
around_suite do |suite|
|
|
311
|
+
with_outer_resource { suite.run }
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
around_suite do |suite|
|
|
315
|
+
with_inner_resource { suite.run }
|
|
316
|
+
end
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
If an `around_suite` hook raises or does not call `suite.run`, Smartest reports a
|
|
320
|
+
suite failure and exits with status `1`.
|
|
321
|
+
|
|
322
|
+
## Test hooks
|
|
323
|
+
|
|
324
|
+
Use `around_test` when each test needs to run inside another block:
|
|
325
|
+
|
|
326
|
+
```ruby
|
|
327
|
+
around_test do |test|
|
|
328
|
+
SomeAutoCloseResource.new do
|
|
329
|
+
test.run
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
The hook receives a run target and must call `test.run` exactly once. It wraps
|
|
335
|
+
fixture setup, the test body, and fixture cleanup.
|
|
336
|
+
|
|
337
|
+
`around_test` is file-scoped when it is written directly in a test file. Smartest
|
|
338
|
+
copies the current file's `around_test` hooks when each `test` is registered, so
|
|
339
|
+
hooks apply to tests defined later in the same file.
|
|
340
|
+
|
|
341
|
+
Define `around_test` inside `around_suite` when the hook should apply to the
|
|
342
|
+
whole run:
|
|
343
|
+
|
|
344
|
+
```ruby
|
|
345
|
+
around_suite do |suite|
|
|
346
|
+
around_test do |test|
|
|
347
|
+
with_some_resource do
|
|
348
|
+
test.run
|
|
349
|
+
end
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
suite.run
|
|
353
|
+
end
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
`around_test` can also register fixture classes or matcher modules for that test
|
|
357
|
+
run:
|
|
358
|
+
|
|
359
|
+
```ruby
|
|
360
|
+
around_test do |test|
|
|
361
|
+
use_fixture LocalFixture
|
|
362
|
+
use_matcher LocalMatcher
|
|
363
|
+
test.run
|
|
364
|
+
end
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
Fixture classes registered from `around_test` must define only test-scoped
|
|
368
|
+
fixtures. If a class defines `suite_fixture`, register it from `around_suite`
|
|
369
|
+
instead so its cache and cleanup belong to the suite lifecycle.
|
|
370
|
+
|
|
371
|
+
`use_fixture` and `use_matcher` are only available inside `around_suite` or
|
|
372
|
+
`around_test` blocks. They are not top-level DSL methods.
|
|
373
|
+
|
|
277
374
|
## Fixtures with teardown
|
|
278
375
|
|
|
279
376
|
Not every fixture needs teardown. For fixtures that do, use `cleanup`.
|
|
@@ -355,7 +452,10 @@ end
|
|
|
355
452
|
|
|
356
453
|
```ruby
|
|
357
454
|
# smartest/test_helper.rb
|
|
358
|
-
|
|
455
|
+
around_suite do |suite|
|
|
456
|
+
use_fixture WebFixture
|
|
457
|
+
suite.run
|
|
458
|
+
end
|
|
359
459
|
```
|
|
360
460
|
|
|
361
461
|
```ruby
|
|
@@ -391,41 +491,34 @@ server cleanup
|
|
|
391
491
|
|
|
392
492
|
## Registering fixture classes
|
|
393
493
|
|
|
394
|
-
Use `use_fixture` from `smartest/test_helper.rb`:
|
|
494
|
+
Use `use_fixture` inside `around_suite` from `smartest/test_helper.rb`:
|
|
395
495
|
|
|
396
496
|
```ruby
|
|
397
|
-
|
|
497
|
+
around_suite do |suite|
|
|
498
|
+
use_fixture AppFixture
|
|
499
|
+
suite.run
|
|
500
|
+
end
|
|
398
501
|
```
|
|
399
502
|
|
|
400
503
|
Multiple fixture classes can be registered:
|
|
401
504
|
|
|
402
505
|
```ruby
|
|
403
|
-
|
|
404
|
-
use_fixture
|
|
405
|
-
use_fixture
|
|
506
|
+
around_suite do |suite|
|
|
507
|
+
use_fixture UserFixture
|
|
508
|
+
use_fixture WebFixture
|
|
509
|
+
use_fixture ApiFixture
|
|
510
|
+
suite.run
|
|
511
|
+
end
|
|
406
512
|
```
|
|
407
513
|
|
|
408
514
|
Fixture names must be unique across registered fixture classes.
|
|
409
515
|
|
|
410
516
|
If two fixture classes define the same fixture name, Smartest raises an error.
|
|
411
517
|
|
|
412
|
-
##
|
|
413
|
-
|
|
414
|
-
Smartest may support simple hooks:
|
|
415
|
-
|
|
416
|
-
```ruby
|
|
417
|
-
before do
|
|
418
|
-
DatabaseCleaner.start
|
|
419
|
-
end
|
|
518
|
+
## Suite hooks and fixture cleanup
|
|
420
519
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
end
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
Hooks are separate from fixture cleanup.
|
|
427
|
-
|
|
428
|
-
Use fixture cleanup for resource-specific teardown:
|
|
520
|
+
Suite hooks are separate from fixture cleanup. Use fixture cleanup for
|
|
521
|
+
resource-specific teardown:
|
|
429
522
|
|
|
430
523
|
```ruby
|
|
431
524
|
fixture :server do
|
|
@@ -435,11 +528,11 @@ fixture :server do
|
|
|
435
528
|
end
|
|
436
529
|
```
|
|
437
530
|
|
|
438
|
-
Use
|
|
531
|
+
Use `around_suite` for broad suite-level execution context:
|
|
439
532
|
|
|
440
533
|
```ruby
|
|
441
|
-
|
|
442
|
-
|
|
534
|
+
around_suite do |suite|
|
|
535
|
+
Async { suite.run }
|
|
443
536
|
end
|
|
444
537
|
```
|
|
445
538
|
|
|
@@ -469,13 +562,16 @@ Dir[File.join(__dir__, "matchers", "**", "*.rb")].sort.each do |matcher_file|
|
|
|
469
562
|
require matcher_file
|
|
470
563
|
end
|
|
471
564
|
|
|
472
|
-
|
|
473
|
-
|
|
565
|
+
around_suite do |suite|
|
|
566
|
+
use_fixture WebFixture
|
|
567
|
+
use_matcher PredicateMatcher
|
|
568
|
+
suite.run
|
|
569
|
+
end
|
|
474
570
|
```
|
|
475
571
|
|
|
476
572
|
The generated helper loads Ruby files under `smartest/fixtures/` and
|
|
477
|
-
`smartest/matchers/` in sorted order. Register fixture classes and
|
|
478
|
-
modules from
|
|
573
|
+
`smartest/matchers/` in sorted order. Register suite-wide fixture classes and
|
|
574
|
+
matcher modules from `around_suite` with `use_fixture` and `use_matcher`.
|
|
479
575
|
|
|
480
576
|
Example:
|
|
481
577
|
|
|
@@ -550,6 +646,8 @@ The intended MVP includes:
|
|
|
550
646
|
- keyword-argument fixture injection
|
|
551
647
|
- fixture dependencies through keyword arguments
|
|
552
648
|
- fixture cleanup
|
|
649
|
+
- suite hooks with `around_suite`
|
|
650
|
+
- test hooks with `around_test`
|
|
553
651
|
- `expect(...).to eq(...)`
|
|
554
652
|
- console reporter
|
|
555
653
|
- CLI runner
|
data/SMARTEST_DESIGN.md
CHANGED
|
@@ -50,7 +50,10 @@ class WebFixture < Smartest::Fixture
|
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
around_suite do |suite|
|
|
54
|
+
use_fixture WebFixture
|
|
55
|
+
suite.run
|
|
56
|
+
end
|
|
54
57
|
```
|
|
55
58
|
|
|
56
59
|
The core decision is:
|
|
@@ -294,7 +297,9 @@ context.instance_exec(**fixtures, &block)
|
|
|
294
297
|
|
|
295
298
|
This keeps the top-level DSL small.
|
|
296
299
|
|
|
297
|
-
Only `test`, `
|
|
300
|
+
Only `test`, `around_suite`, and `around_test` should be globally available when
|
|
301
|
+
using `smartest/autorun`. `use_fixture` and `use_matcher` are available only
|
|
302
|
+
inside hook execution contexts.
|
|
298
303
|
|
|
299
304
|
## Core architecture
|
|
300
305
|
|
|
@@ -543,8 +548,11 @@ class AdminFixture < Smartest::Fixture
|
|
|
543
548
|
end
|
|
544
549
|
end
|
|
545
550
|
|
|
546
|
-
|
|
547
|
-
use_fixture
|
|
551
|
+
around_suite do |suite|
|
|
552
|
+
use_fixture UserFixture
|
|
553
|
+
use_fixture AdminFixture
|
|
554
|
+
suite.run
|
|
555
|
+
end
|
|
548
556
|
```
|
|
549
557
|
|
|
550
558
|
Error:
|
|
@@ -853,7 +861,70 @@ Useful metadata later:
|
|
|
853
861
|
|
|
854
862
|
Hooks are separate from fixtures.
|
|
855
863
|
|
|
856
|
-
|
|
864
|
+
Supported suite API:
|
|
865
|
+
|
|
866
|
+
```ruby
|
|
867
|
+
around_suite do |suite|
|
|
868
|
+
Async do
|
|
869
|
+
suite.run
|
|
870
|
+
end
|
|
871
|
+
end
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
`around_suite` wraps the full suite body, including all tests and suite fixture
|
|
875
|
+
cleanup. The hook receives a run target and must call `suite.run` exactly once.
|
|
876
|
+
Multiple hooks compose in registration order, with the first hook as the
|
|
877
|
+
outermost wrapper.
|
|
878
|
+
|
|
879
|
+
Supported per-test API:
|
|
880
|
+
|
|
881
|
+
```ruby
|
|
882
|
+
around_test do |test|
|
|
883
|
+
SomeAutoCloseResource.new do
|
|
884
|
+
test.run
|
|
885
|
+
end
|
|
886
|
+
end
|
|
887
|
+
```
|
|
888
|
+
|
|
889
|
+
When `around_test` is written directly in a test file, Smartest treats it as
|
|
890
|
+
file-scoped by snapshotting the file's current around-test hooks into each
|
|
891
|
+
`TestCase` at test registration time. Hooks defined later in the file apply only
|
|
892
|
+
to later tests.
|
|
893
|
+
|
|
894
|
+
`around_test` can also be registered inside `around_suite`. In that case the hook
|
|
895
|
+
is suite-wide and applies when `suite.run` executes:
|
|
896
|
+
|
|
897
|
+
```ruby
|
|
898
|
+
around_suite do |suite|
|
|
899
|
+
around_test do |test|
|
|
900
|
+
TestServer.run do
|
|
901
|
+
test.run
|
|
902
|
+
end
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
suite.run
|
|
906
|
+
end
|
|
907
|
+
```
|
|
908
|
+
|
|
909
|
+
`use_fixture` and `use_matcher` are not top-level DSL methods. They are available
|
|
910
|
+
inside `around_suite` and `around_test` contexts:
|
|
911
|
+
|
|
912
|
+
```ruby
|
|
913
|
+
around_test do |test|
|
|
914
|
+
use_fixture LocalFixture
|
|
915
|
+
use_matcher LocalMatcher
|
|
916
|
+
test.run
|
|
917
|
+
end
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
For `around_test`, those registrations are test-run local and must happen before
|
|
921
|
+
`test.run`.
|
|
922
|
+
|
|
923
|
+
Fixture classes registered from `around_test` must not define `suite_fixture`.
|
|
924
|
+
Suite-scoped fixtures need suite-level cache and cleanup ownership, so classes
|
|
925
|
+
with suite-scoped fixtures must be registered from `around_suite`.
|
|
926
|
+
|
|
927
|
+
Potential simpler per-test API:
|
|
857
928
|
|
|
858
929
|
```ruby
|
|
859
930
|
before do
|
|
@@ -889,10 +960,29 @@ fixture cleanup
|
|
|
889
960
|
|
|
890
961
|
This needs a final decision later.
|
|
891
962
|
|
|
892
|
-
For MVP, hooks can be omitted.
|
|
893
|
-
|
|
894
963
|
Fixture cleanup already handles resource-specific teardown.
|
|
895
964
|
|
|
965
|
+
### Around-test parallelism note
|
|
966
|
+
|
|
967
|
+
The file-scoped `around_test` design is intended to remain compatible with
|
|
968
|
+
future parallel execution if it is hardened in these directions:
|
|
969
|
+
|
|
970
|
+
- keep registration protected by a `Mutex` when tests may be loaded from
|
|
971
|
+
multiple threads
|
|
972
|
+
- use copy-on-write arrays for `around_test` hooks by file
|
|
973
|
+
- snapshot the current file-local hook stack into each `TestCase` at registration
|
|
974
|
+
time
|
|
975
|
+
- treat `TestCase` as immutable after registration
|
|
976
|
+
- expose `use_fixture` and `use_matcher` through a per-run `TestRun` object, not
|
|
977
|
+
by mutating the global suite registry during test execution
|
|
978
|
+
- snapshot the suite's fixture classes and matcher modules before a test starts
|
|
979
|
+
- keep test-run fixture and matcher additions local to that run
|
|
980
|
+
|
|
981
|
+
That shape lets multiple tests execute concurrently by reading immutable
|
|
982
|
+
`TestCase` state and using per-test fixture/matcher registries. The current
|
|
983
|
+
implementation can be simpler, but it should not rely on refinements or global
|
|
984
|
+
method rewriting for file-local behavior.
|
|
985
|
+
|
|
896
986
|
## Scoping
|
|
897
987
|
|
|
898
988
|
Fixtures are test-scoped by default.
|
|
@@ -1073,6 +1163,11 @@ require "smartest/autorun"
|
|
|
1073
1163
|
Dir[File.join(__dir__, "fixtures", "**", "*.rb")].sort.each do |fixture_file|
|
|
1074
1164
|
require fixture_file
|
|
1075
1165
|
end
|
|
1166
|
+
|
|
1167
|
+
around_suite do |suite|
|
|
1168
|
+
use_fixture AppFixture
|
|
1169
|
+
suite.run
|
|
1170
|
+
end
|
|
1076
1171
|
```
|
|
1077
1172
|
|
|
1078
1173
|
```ruby
|
|
@@ -1098,8 +1193,6 @@ end
|
|
|
1098
1193
|
# smartest/example_test.rb
|
|
1099
1194
|
require "test_helper"
|
|
1100
1195
|
|
|
1101
|
-
use_fixture AppFixture
|
|
1102
|
-
|
|
1103
1196
|
test("GET /health") do |client:|
|
|
1104
1197
|
expect(client.get("/health").status).to eq(200)
|
|
1105
1198
|
end
|
|
@@ -1117,7 +1210,6 @@ Possible future features:
|
|
|
1117
1210
|
- richer matchers
|
|
1118
1211
|
- block expectations
|
|
1119
1212
|
- `raise_error`
|
|
1120
|
-
- hooks
|
|
1121
1213
|
- file-scoped fixtures
|
|
1122
1214
|
- parallel execution
|
|
1123
1215
|
- watch mode
|
data/lib/smartest/dsl.rb
CHANGED
|
@@ -3,24 +3,31 @@
|
|
|
3
3
|
module Smartest
|
|
4
4
|
module DSL
|
|
5
5
|
def test(name, **metadata, &block)
|
|
6
|
+
location = caller_locations(1, 1).first
|
|
7
|
+
|
|
6
8
|
Smartest.suite.tests.add(
|
|
7
9
|
TestCase.new(
|
|
8
10
|
name: name,
|
|
9
11
|
metadata: metadata,
|
|
10
12
|
block: block,
|
|
11
|
-
location:
|
|
13
|
+
location: location,
|
|
14
|
+
around_test_hooks: Smartest.suite.around_test_hooks_for(location)
|
|
12
15
|
)
|
|
13
16
|
)
|
|
14
17
|
end
|
|
15
18
|
|
|
16
|
-
def
|
|
17
|
-
|
|
19
|
+
def around_suite(&block)
|
|
20
|
+
raise ArgumentError, "around_suite block is required" unless block
|
|
21
|
+
|
|
22
|
+
Smartest.suite.around_suite_hooks << block
|
|
18
23
|
end
|
|
19
24
|
|
|
20
|
-
def
|
|
21
|
-
|
|
25
|
+
def around_test(&block)
|
|
26
|
+
raise ArgumentError, "around_test block is required" unless block
|
|
27
|
+
|
|
28
|
+
Smartest.suite.add_around_test_hook(caller_locations(1, 1).first, block)
|
|
22
29
|
end
|
|
23
30
|
|
|
24
|
-
private :test, :
|
|
31
|
+
private :test, :around_suite, :around_test
|
|
25
32
|
end
|
|
26
33
|
end
|
data/lib/smartest/errors.rb
CHANGED
|
@@ -48,5 +48,21 @@ module Smartest
|
|
|
48
48
|
|
|
49
49
|
class InvalidFixtureParameterError < Error; end
|
|
50
50
|
|
|
51
|
+
class AroundSuiteRunError < Error; end
|
|
52
|
+
|
|
53
|
+
class AroundTestFixtureScopeError < Error
|
|
54
|
+
def initialize(fixture_class, fixture_names)
|
|
55
|
+
class_name = fixture_class.name || fixture_class.inspect
|
|
56
|
+
names = fixture_names.map { |fixture_name| ":#{fixture_name}" }.join(", ")
|
|
57
|
+
|
|
58
|
+
super(
|
|
59
|
+
"#{class_name} cannot be registered from around_test because it defines suite-scoped fixtures: #{names}. " \
|
|
60
|
+
"Register fixture classes with suite_fixture from around_suite instead."
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class AroundTestRunError < Error; end
|
|
66
|
+
|
|
51
67
|
class AssertionFailed < Error; end
|
|
52
68
|
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Smartest
|
|
4
|
+
class AroundSuiteContext
|
|
5
|
+
def initialize(suite)
|
|
6
|
+
@suite = suite
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def call(hook, suite_run)
|
|
10
|
+
@suite.around_suite_hook do
|
|
11
|
+
instance_exec(suite_run, &hook)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def use_fixture(klass)
|
|
18
|
+
@suite.fixture_classes.add(klass)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def use_matcher(matcher_module)
|
|
22
|
+
@suite.matcher_modules.add(matcher_module)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def around_test(&block)
|
|
26
|
+
raise ArgumentError, "around_test block is required" unless block
|
|
27
|
+
|
|
28
|
+
@suite.add_around_test_hook(caller_locations(1, 1).first, block)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class AroundTestContext
|
|
33
|
+
def initialize(test_run)
|
|
34
|
+
@test_run = test_run
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def call(hook, run_target = @test_run)
|
|
38
|
+
instance_exec(run_target, &hook)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def use_fixture(klass)
|
|
44
|
+
@test_run.add_fixture_class(klass)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def use_matcher(matcher_module)
|
|
48
|
+
@test_run.add_matcher_module(matcher_module)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -18,7 +18,10 @@ module Smartest
|
|
|
18
18
|
require matcher_file
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
around_suite do |suite|
|
|
22
|
+
use_matcher PredicateMatcher
|
|
23
|
+
suite.run
|
|
24
|
+
end
|
|
22
25
|
RUBY
|
|
23
26
|
"smartest/matchers/predicate_matcher.rb" => <<~RUBY,
|
|
24
27
|
# frozen_string_literal: true
|
data/lib/smartest/reporter.rb
CHANGED
|
@@ -19,14 +19,19 @@ module Smartest
|
|
|
19
19
|
@io.puts "#{mark} #{result.test_case.name}"
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def finish(results, suite_cleanup_errors: [])
|
|
22
|
+
def finish(results, suite_cleanup_errors: [], suite_errors: [])
|
|
23
23
|
failures = results.select(&:failed?)
|
|
24
24
|
|
|
25
25
|
report_failures(failures) if failures.any?
|
|
26
|
+
report_suite_errors(suite_errors) if suite_errors.any?
|
|
26
27
|
report_suite_cleanup_errors(suite_cleanup_errors) if suite_cleanup_errors.any?
|
|
27
28
|
|
|
28
29
|
@io.puts
|
|
29
30
|
summary = "#{results.count} #{results.count == 1 ? 'test' : 'tests'}, #{results.count(&:passed?)} passed, #{failures.count} failed"
|
|
31
|
+
if suite_errors.any?
|
|
32
|
+
suite_label = suite_errors.count == 1 ? "suite failure" : "suite failures"
|
|
33
|
+
summary = "#{summary}, #{suite_errors.count} #{suite_label}"
|
|
34
|
+
end
|
|
30
35
|
if suite_cleanup_errors.any?
|
|
31
36
|
cleanup_label = suite_cleanup_errors.count == 1 ? "suite cleanup" : "suite cleanups"
|
|
32
37
|
summary = "#{summary}, #{suite_cleanup_errors.count} #{cleanup_label} failed"
|
|
@@ -50,6 +55,18 @@ module Smartest
|
|
|
50
55
|
end
|
|
51
56
|
end
|
|
52
57
|
|
|
58
|
+
def report_suite_errors(errors)
|
|
59
|
+
@io.puts
|
|
60
|
+
@io.puts "Suite failures:"
|
|
61
|
+
@io.puts
|
|
62
|
+
|
|
63
|
+
errors.each_with_index do |error, index|
|
|
64
|
+
@io.puts "#{index + 1}) suite"
|
|
65
|
+
report_error(error)
|
|
66
|
+
@io.puts
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
53
70
|
def report_suite_cleanup_errors(errors)
|
|
54
71
|
@io.puts
|
|
55
72
|
@io.puts "Suite cleanup failures:"
|