2 The Mock Reference
This document describes the complete API of the mock library. For a gentler introduction and use cases, see The Mock Guide.
2.1 Core Mock API
procedure
(mock [ #:behavior behavior-proc #:name name #:external-histories histories]) → mock? behavior-proc : procedure? = #f name : symbol? = #f histories : (listof call-history?) = (list)
> (define quotient/remainder-mock (mock #:behavior quotient/remainder)) > (quotient/remainder-mock 10 3)
3
1
> (mock? quotient/remainder-mock) #t
> (define uncallable-mock (mock #:name 'uncallable-mock)) > (uncallable-mock 1 2 3 #:foo 'bar #:bar "blah") uncallable-mock: unexpectedly called with arguments
positional:
1
2
3
keyword:
#:bar: "blah"
#:foo: 'bar
> (define h (call-history)) > (define m1 (mock #:name 'm1 #:behavior void #:external-histories (list h))) > (define m2 (mock #:name 'm2 #:behavior void #:external-histories (list h))) > (m1 'foo) > (m2 'bar) > (m1 'baz) > (call-history-calls h)
(list
(mock-call 'm1 (arguments 'foo) '(#<void>))
(mock-call 'm2 (arguments 'bar) '(#<void>))
(mock-call 'm1 (arguments 'baz) '(#<void>)))
Added in version 2.0 of package mock.
procedure
(current-mock-name) → (or/c symbol? #f)
> (current-mock-name) current-mock-name: can't be called outside mock behavior
Added in version 1.1 of package mock.
procedure
> (define keyword-set (make-keyword-procedure (λ (kws _) (define (call-kws call) (hash-keys (arguments-keyword (mock-call-args call)))) (define prev-kws (append-map call-kws (current-mock-calls))) (apply set (append kws prev-kws))))) > (define kw-set-mock (mock #:behavior keyword-set)) > (kw-set-mock #:foo 'bar) (set '#:foo)
> (kw-set-mock #:baz "blah") (set '#:foo '#:baz)
> (current-mock-calls) current-mock-calls: can't be called outside mock behavior
Added in version 1.2 of package mock.
procedure
> (define (log-count) (printf "Mock called ~a times previously" (current-mock-num-calls))) > (define count-mock (mock #:behavior log-count)) > (count-mock) Mock called 0 times previously
> (count-mock) Mock called 1 times previously
> (mock-reset! count-mock) > (count-mock) Mock called 0 times previously
> (current-mock-num-calls) current-mock-num-calls: can't be called outside mock
behavior
Added in version 1.3 of package mock.
procedure
(mock-reset! m) → void?
m : mock?
> (define void-mock (mock #:behavior void)) > (void-mock 'foo) > (mock-num-calls void-mock) 1
> (mock-reset! void-mock) > (mock-num-calls void-mock) 0
syntax
(with-mock-behavior ([mock-expr behavior-expr] ...) body ...)
mock-expr : mock?
behavior-expr : procedure?
> (define num-mock (mock #:behavior add1)) > (num-mock 10) 11
> (with-mock-behavior ([num-mock sub1]) (num-mock 10)) 9
> (num-mock 10) 11
> (mock-calls num-mock)
(list
(mock-call #f (arguments 10) '(11))
(mock-call #f (arguments 10) '(9))
(mock-call #f (arguments 10) '(11)))
procedure
(mock-call [ #:name name #:args args #:results results]) → mock-call? name : (or/c symbol? #f) = #f args : arguments? = (arguments) results : list? = (list)
procedure
(mock-call? v) → boolean?
v : any/c
procedure
(mock-call-args call) → arguments?
call : mock-call?
procedure
(mock-call-name call) → (or/c symbol? #f)
call : mock-call?
procedure
(mock-call-results call) → list?
call : mock-call?
Changed in version 2.0 of package mock: Changed from a plain struct to a keyword-based constructor and added a name field.
procedure
(mock-calls m) → (listof mock-call?)
m : mock?
> (define void-mock (mock #:behavior void)) > (void-mock 10 3) > (void-mock 'foo 'bar 'baz) > (mock-calls void-mock)
(list
(mock-call #f (arguments 10 3) '(#<void>))
(mock-call #f (arguments 'foo 'bar 'baz) '(#<void>)))
procedure
(mock-called-with? m args) → boolean?
m : mock? args : arguments?
> (define ~a-mock (mock #:behavior ~a)) > (~a-mock 0 #:width 3 #:align 'left) "0 "
> (mock-called-with? ~a-mock (arguments 0 #:align 'left #:width 3)) #t
procedure
m : mock?
> (define void-mock (mock #:behavior void)) > (void-mock 10 3) > (void-mock 'foo 'bar 'baz) > (mock-num-calls void-mock) 2
struct
(struct exn:fail:unexpected-arguments exn:fail (args) #:transparent) args : arguments?
2.2 Behavior Construction Utilities
procedure
(const/kw v) → procedure?
v : any/c
Added in version 1.5 of package mock.
value
Added in version 1.5 of package mock.
procedure
(const-raise v) → procedure?
v : any/c
> ((const-raise 'a) 1) uncaught exception: a
> ((const-raise 'a) #:foo 2) uncaught exception: a
Added in version 1.5 of package mock.
procedure
(const-raise-exn [ #:message msg #:constructor ctor]) → procedure? msg : string? = "failure"
ctor : (-> string? continuation-mark-set? any/c) = make-exn:fail
> ((const-raise-exn) 1) failure
> ((const-raise-exn #:message "some other failure") #:foo 2) some other failure
> (define (exn/custom-message msg marks) (make-exn:fail (format "custom: ~a" msg) marks)) > ((const-raise-exn #:constructor exn/custom-message) #:bar 3) custom: failure
Added in version 1.5 of package mock.
procedure
(const-series v ... [#:reset? reset?]) → procedure?
v : any/c reset? : boolean? = #f
> (define ab-proc (const-series 'a 'b)) > (ab-proc 1) 'a
> (ab-proc #:foo 2) 'b
> (ab-proc #:bar 3) raise-arguments-error: contract violation
expected: string?
given: 'num-calls
argument position: 3rd
other arguments...:
'const-series
"called more times than number of arguments"
2
> (define ab-proc (const-series 'a 'b #:repeat? #t)) > (ab-proc) 'a
> (ab-proc) 'b
> (ab-proc) 'a
Added in version 1.5 of package mock.
2.3 Mock Call Histories
procedure
procedure
(call-history? v) → boolean?
v : any/c
procedure
(call-history-record! history call) → void?
history : call-history? call : mock-call?
procedure
(call-history-calls history) → (listof mock-call?)
history : call-history?
> (define history (call-history))
> (call-history-record! history (mock-call #:name 'foo #:args (arguments 1 2 3) #:results (list 'foo)))
> (call-history-record! history (mock-call #:name 'bar #:args (arguments 10 20 30) #:results (list 'bar))) > (call-history-calls history)
(list
(mock-call 'foo (arguments 1 2 3) '(foo))
(mock-call 'bar (arguments 10 20 30) '(bar)))
procedure
(call-history-count history) → (listof mock-call?)
history : call-history?
> (define history (call-history)) > (call-history-count history) 0
> (call-history-record! history (mock-call)) > (call-history-count history) 1
procedure
(call-history-reset! history) → void?
history : call-history?
> (define history (call-history)) > (call-history-record! history (mock-call)) > (call-history-reset! history) > (call-history-calls history) '()
2.4 Opaque Values
Often libraries work with values whose representations are unknown to clients, values which can only be constructed via those libraries. For example, a database library may define a database connection value and a database-connection? predicate, and only allow construction of connections via a database-connect! procedure. This is powerful for library creators but tricky for testers, as tests likely don’t want to spin up a database just to verify they’ve called the library procedures correctly. The mock library provides utilities for defining opaque values that mocks can interact with.
syntax
(define-opaque clause ...)
clause = id
> (define-opaque foo bar) > foo #<foo>
> foo? #<procedure:foo?>
> (foo? foo) #t
> (equal? foo foo) #t
> (define-opaque foo #:name FOO) > foo #<FOO>
> foo? #<procedure:FOO?>
Additionally, define/mock provides syntax for defining opaque values.
2.5 Mocking Dependencies
Mocks by themselves provide useful low-level building blocks, but often to use them a function needs to be implemented twice - once using mocks for the purpose of testing, and once using real functions to provide actual functionality. The mock library provides a shorthand syntax for defining both implementations at once.
syntax
(define/mock header opaque-clause history-clause mock-clause ... body ...)
header = id | (header arg ...) | (header arg ... . rest) opaque-clause =
| #:opaque opaque-id:id | #:opaque (opaque-id:id ...) history-clause =
| #:history history-id:id mock-clause = #:mock mock-id mock-as mock-default | #:mock-param param-id mock-as mock-default mock-as =
| #:as mock-as-id mock-default =
| #:with-behavior behavior-expr
behavior-expr : procedure?
> (define/mock (foo) #:mock bar #:as bar-mock #:with-behavior (const "wow!") (bar)) > (define (bar) "bam!") > (displayln (foo)) bam!
> (with-mocks foo (displayln (foo)) (displayln (mock-calls bar-mock)))
wow!
(#(struct:mock-call bar-mock (arguments) (wow!)))
> (define/mock (foo/opaque) #:opaque special #:mock bar #:as bar-mock #:with-behavior (const special) (bar)) > (define (bar) "bam!") > special special: undefined;
cannot reference an identifier before its definition
in module: 'program
> (foo/opaque) "bam!"
> (with-mocks foo/opaque (displayln special) (displayln (special? (foo/opaque))))
#<special>
#t
> (define/mock (foo/default-binding) #:mock bar #:with-behavior (const "wow!") (bar)) > (define (bar) "bam!") > (foo/default-binding) "bam!"
> (with-mocks foo/default-binding (displayln (foo/default-binding)) (displayln (mock-calls bar)))
wow!
(#(struct:mock-call bar (arguments) (wow!)))
> (define/mock (foo/no-behavior) #:mock bar (bar)) > (define (bar) "bam!") > (foo/no-behavior) "bam!"
> (with-mocks foo/no-behavior (foo/no-behavior)) bar: unexpectedly called with arguments
positional:
keyword:
> (define current-bar (make-parameter (const "bam!"))) > (define (bar) ((current-bar)))
> (define/mock (foo/param) #:mock-param current-bar #:with-behavior (const "wow!") (bar)) > (foo/param) "bam!"
> (with-mocks foo/param (displayln (foo/param))) wow!
Changed in version 2.0 of package mock: Added #:call-history option
Changed in version 2.1 of package mock: Added #:mock-param option
syntax
(with-mocks proc/mocks-id body ...)
2.6 Stub Implementations
Mocks and define/mock make it possible to test procedures before the procedures they call have been implemented. However, if the procedures called haven’t been defined, a compilation error will occur despite the fact that they’re not used in test. To assist with this, the mock library provides syntax for defining stubs, procedures that haven’t been implemented and throw immediately when called. The term "stub" is used in different ways by different languages and libraries, but that is the definition used by this library.
syntax
(stub header ...)
header = id | (header arg ...) | (header arg ... . rest)
> (stub foo (bar v) ((baz k) #:blah v)) > (foo 1 2 #:a 'b) procedure foo hasn't been implemented
> (bar 1) procedure bar hasn't been implemented
> (bar 1 2) bar: arity mismatch;
the expected number of arguments does not match the given
number
expected: 1
given: 2
arguments...:
1
2
> (baz 1) #<procedure:baz>
> ((baz 1) #:blah "blahhhh") procedure baz hasn't been implemented
struct
(struct exn:fail:not-implemented exn:fail () #:transparent)