Test Fixtures for RackUnit
This library defines fixtures, resources used in test cases that are automatically created and destroyed at the beginning and end of each test case. Fixtures are built on top of rackunit test cases and the disposable library; familiarity with the two is assumed in this document.
(define-fixture tmpdir (disposable-directory)) (define-fixture tmpfile (disposable-file)) (test-case/fixture "tests" #:fixture tmpdir #:fixture tmpfile (test-case "some-test" ... use (current-tmpdir) and (current-tmpfile) ...) (test-case "other-test" ... use different (current-tmpdir) and (current-tmpfile) ...))
Source code for this library is available on Github and is provided under the terms of the Apache License 2.0.
Warning! This library is experimental; it may change in backwards incompatible ways without notice. As such, now is the best time for feedback and suggestions so feel free to open a repository issue or reach out to me directly.
1 Overview of Collections and Modules
This package provides several modules, all in the fixture collection:
fixture - Re-provides the exports of fixture/base and fixture/rackunit.
fixture/base - Base definitions of fixtures and all testing framework agnostic forms.
fixture/rackunit - Tools for using fixtures with rackunit.
2 Data Model
(require fixture/base) | package: fixture |
A fixture is an external resource that must be properly initialized and disposed of for a test. Fixtures are essentially a pair of a disposable defining the external resource and a parameter that is set for each test to an instance of the disposable.
Additionally, fixtures may have fixture info; custom metadata about the current value of the fixture that can be used in test failure messages. Each fixture defines what info values it provides and there are no restrictions on the kind of values a fixture may use for info, although it’s expected that calling write on them produces something relatively useful.
> (define (example-info n) (format "example value of ~v" n))
> (define ex (fixture 'ex example-disposable #:info-proc example-info))
> (call/fixture ex (thunk (displayln (fixture-value ex)) (displayln (fixture-info ex))))
Allocated 29
29
example value of 29
Deallocated 29
> (fixture-value ex) fixture-value: contract violation
expected: fixture-initialized?
given: #<fixture>
in: an and/c case of
the 1st argument of
(->
(and/c fixture? fixture-initialized?)
any/c)
contract from: <pkgs>/fixture/base.rkt
blaming: program
(assuming the contract is correct)
at: <pkgs>/fixture/base.rkt:14:3
procedure
(fixture-initialized? fix) → boolean?
fix : fixture?
syntax
(define-fixture id disposable-expr fixture-option ...)
fixture-option = #:accessor-id accessor-id | #:info-proc info-proc-expr
disposable-expr : disposable?
info-proc-expr : (-> any/c any/c)
> (define (example-info n) (format "example value of ~v" n)) > (define-fixture ex example-disposable #:info-proc example-info)
> (call/fixture ex (thunk (displayln (current-ex)) (displayln (fixture-info ex))))
Allocated 85
85
example value of 85
Deallocated 85
> (current-ex) raise-argument-error: contract violation
expected: exact-nonnegative-integer?
given: "fixture"
procedure
(fixture-value fix) → any/c
fix : (and/c fixture? fixture-initialized?)
procedure
(call/fixture fix proc) → any
fix : fixture? proc : (-> any)
> (define-fixture ex example-disposable) > (call/fixture ex (thunk (* (current-ex) (current-ex))))
Allocated 53
Deallocated 53
2809
procedure
(fixture-name fix) → symbol?
fix : fixture?
procedure
(fixture-info fix) → any/c
fix : (and/c fixture? fixture-initialized?)
> (struct example-info (value) #:transparent) > (define-fixture ex example-disposable #:info-proc example-info) > (call/fixture ex (thunk (fixture-info ex)))
Allocated 18
Deallocated 18
(example-info 18)
3 RackUnit Integration
(require fixture/rackunit) | package: fixture |
syntax
(test-begin/fixture fixture-clause ... body ...+)
fixture-clause = #:fixture fixture-expr
fixture-expr : fixture?
> (define-fixture ex1 example-disposable) > (define-fixture ex2 example-disposable) > (define (ex-sum) (+ (current-ex1) (current-ex2)))
> (test-begin/fixture #:fixture ex1 #:fixture ex2 (displayln (ex-sum)) (test-case "nested" (displayln (ex-sum))))
Allocated 17
Allocated 18
35
Allocated 57
Allocated 36
93
Deallocated 36
Deallocated 57
Deallocated 18
Deallocated 17
Additionally, test failures are augmented with a check-info with the name 'fixtures. The info’s value is a nested-info containing one check info for each fixture used; that info’s name and value correspond to the fixture’s name and its fixture info at the time the test failure occurred.
> (define-fixture file1 (disposable-file)) > (define-fixture file2 (disposable-file))
> (test-begin/fixture #:fixture file1 #:fixture file2 (check-equal? 1 2))
--------------------
FAILURE
fixtures:
file1: #<path:/var/tmp/rkttmp17466742431746674244736>
file2: #<path:/var/tmp/rkttmp17466742441746674244732>
name: check-equal?
location: eval:3:0
actual: 1
expected: 2
--------------------
syntax
(test-case/fixture name fixture-clause ... body ...+)
name = string-literal fixture-clause = #:fixture fixture-expr
fixture-expr : fixture?