Test Fixtures for Rack  Unit
1 Overview of Collections and Modules
2 Data Model
call/  fixture
3 Rack  Unit Integration
test-begin/  fixture
test-case/  fixture

Test Fixtures for RackUnit

 (require fixture) package: fixture

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:

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.


(fixture name disp [#:info-proc info-proc])  fixture?

  name : symbol?
  disp : disposable?
  info-proc : (-> any/c any/c) = values
Returns a fixture named name that provides instances of values created with disp. The info-proc defines the fixture’s info, and is called with the current value of the fixture to when fixture-info is called. Fixtures must be initialized with call/fixture before use; attempting to access the current value before initialization raises a contract error.

> (define (example-info n) (format "example value of ~v" n))
> (define ex
    (fixture 'ex example-disposable #:info-proc example-info))
> (call/fixture ex
     (displayln (fixture-value ex))
     (displayln (fixture-info ex))))

Allocated 14


example value of 14

Deallocated 14

> (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?)


  contract from: <pkgs>/fixture/base.rkt

  blaming: program

   (assuming the contract is correct)

  at: <pkgs>/fixture/base.rkt:14:3


(fixture? v)  boolean?

  v : any/c
Returns #t if v is a fixture, returns #f otherwise.


(fixture-initialized? fix)  boolean?

  fix : fixture?
Returns #t if fix is currently initialized with call/fixture, returns #f otherwise.


(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)
Binds id to a fixture with name 'id, with disposable disposable-expr, and with its fixture info defined by info-proc-expr. Additionally, binds accessor-id to a shorthand function that call fixture-value on id. If accessor-id is not provided, it defaults to current-id. Each fixture-option may only be provided once.

> (define (example-info n) (format "example value of ~v" n))
> (define-fixture ex example-disposable #:info-proc example-info)
> (call/fixture ex
     (displayln (current-ex))
     (displayln (fixture-info ex))))

Allocated 57


example value of 57

Deallocated 57

> (current-ex)

raise-argument-error: contract violation

  expected: exact-nonnegative-integer?

  given: "fixture"


(fixture-value fix)  any/c

  fix : (and/c fixture? fixture-initialized?)
Returns the current value of fix, or #f if the fixture has not been initialized.


(call/fixture fix proc)  any

  fix : fixture?
  proc : (-> any)
Initializes fix to a new instance of the fixture’s disposable within the body of proc, disposing of the instance of the fixture after calling proc. Returns whatever values are returned by proc. Within the dynamic extend of proc, fixture-initialized? returns #t. Multiple uses of call/fixture may be nested, but a nested use initializes fix to a different instance of disp.

> (define-fixture ex example-disposable)
> (call/fixture ex (thunk (* (current-ex) (current-ex))))

Allocated 69

Deallocated 69



(fixture-name fix)  symbol?

  fix : fixture?
Returns the name of fix.


(fixture-info fix)  any/c

  fix : (and/c fixture? fixture-initialized?)
Returns fix’s current fixture info by applying fix’s fixture info procedure to the current value of the fixture.

> (struct example-info (value) #:transparent)
> (define-fixture ex example-disposable #:info-proc example-info)
> (call/fixture ex (thunk (fixture-info ex)))

Allocated 45

Deallocated 45

(example-info 45)

3 RackUnit Integration

 (require fixture/rackunit) package: fixture


(test-begin/fixture fixture-clause ... body ...+)

fixture-clause = #:fixture fixture-expr
  fixture-expr : fixture?
Like test-begin, but with support for fixtures. Within the given body forms, current-test-case-around is parameterized to a function that wraps the test in a call/fixture expression once for each fixture-expr. Every test found in the body forms, including the outer test-begin, is allocated its own instance of each fixture. Fixtures are allocated in order from top to bottom and deallocated in reverse.

> (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 81


Allocated 41

Allocated 0


Deallocated 0

Deallocated 41

Deallocated 81

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))




  file1:      #<path:/var/tmp/rkttmp16267186631626718666645>

  file2:      #<path:/var/tmp/rkttmp16267186661626718666636>

name:       check-equal?

location:   eval:3:0

actual:     1

expected:   2



(test-case/fixture name fixture-clause ... body ...+)

name = string-literal
fixture-clause = #:fixture fixture-expr
  fixture-expr : fixture?
Like test-begin/fixture, but for test-case instead of test-begin.