Mocks
(require mock) | package: jack-mock |
This library includes functions and forms for working with mocks. A mock is a "fake" function used in place of the real thing during testing to simplify the test and ensure only a single unit and not it’s complex dependencies is being tested. Mocks are most useful for testing code that calls side-effectful operations and IO.
source code: https://github.com/jackfirth/racket-mock
1 Basic Mock Construction
procedure
proc : procedure?
procedure
(mock-calls mock) → (listof mock-call?)
mock : mock?
> (define displayln-mock (make-mock displayln))
> (mock-calls displayln-mock) '()
> (displayln-mock "foo") foo
> (mock-calls displayln-mock) '(#s(mock-call ("foo") (#<void>)))
> (define quotient/remainder-mock (make-mock quotient/remainder))
> (quotient/remainder-mock 10 3)
3
1
> (quotient/remainder-mock 3 2)
1
1
> (mock-calls quotient/remainder-mock) '(#s(mock-call (3 2) (1 1)) #s(mock-call (10 3) (3 1)))
procedure
(mock-called-with? args mock) → boolean?
args : list? mock : mock?
> (define displayln-mock (make-mock displayln))
> (mock-called-with? '("foo") displayln-mock) #f
> (displayln-mock "foo") foo
> (mock-called-with? '("foo") displayln-mock) #t
> (require racket/format)
> (define ~a-mock (make-mock ~a))
> (~a-mock 0 #:width 3 #:align 'left) "0 "
> (mock-called-with? '(0 [#:align left] [#:width 3]) ~a-mock) #t
> (mock-called-with? '(0 [#:width 3] [#:align left]) ~a-mock) #t
procedure
(mock-num-calls mock) → exact-nonnegative-integer?
mock : mock?
> (define displayln-mock (make-mock displayln))
> (mock-num-calls displayln-mock) 0
> (displayln-mock "foo") foo
> (mock-num-calls displayln-mock) 1
2 RackUnit Checks for Mocks
procedure
(check-mock-called-with? args mock) → void?
args : list? mock : mock?
> (check-mock-called-with? '(some args) (void-mock))
--------------------
FAILURE
name: check-mock-called-with?
location: (#<path:/home/racket/build-pkgs/user/.racket/6.3.90.900/pkgs/jack-mock/mock/private/check.rkt> 10 4 138 23)
expression: (check-mock-called-with? args2 mock3)
params: ((some args) #<procedure:...t/private/kw.rkt:213:14>)
Check failure
--------------------
procedure
(check-mock-num-calls n mock) → void?
n : exact-positive-integer? mock : mock?
> (check-mock-num-calls 1 (void-mock))
--------------------
FAILURE
name: check-mock-num-calls
location: (#<path:/home/racket/build-pkgs/user/.racket/6.3.90.900/pkgs/jack-mock/mock/private/check.rkt> 11 4 189 20)
expression: (check-mock-num-calls expected-num-calls15 mock16)
params: (1 #<procedure:...t/private/kw.rkt:213:14>)
Check failure
--------------------
3 Mock Constructors
> (define a-void-mock (void-mock))
> (a-void-mock)
> (a-void-mock 1 2 3)
> (mock-num-calls a-void-mock) 2
procedure
(const-mock v) → mock?
v : any/c
> (define foo-mock (const-mock 'foo))
> (foo-mock 'bar) 'foo
4 Mocking Out Functions for Testing
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. These syntactic forms provide shorthands for defining both implementations at once.
syntax
(define/mock header ([mock-id mock-expr] ...) body ...)
header = id | (header arg ...)
mock-expr : mock?
> (module m racket (require mock) (define/mock (displayln-twice v) ([displayln (void-mock)]) (displayln v) (displayln v)) (displayln-twice "sent to real displayln") (mock? displayln) (module+ test (displayln-twice "sent to mock displayln") (mock? displayln)))
> (require 'm)
sent to real displayln
sent to real displayln
#f
> (require (submod 'm test))
sent to mock displayln
sent to mock displayln
#f
syntax
(define/mock-as header (mock-clause ...) body ...)
header = id | (header arg ...) mock-clause = [mock-id mock-value-id mock-expr]
mock-expr : mock?
> (module m racket (require mock) (define/mock-as (displayln-twice v) ([displayln displayln-mock (void-mock)]) (displayln v) (displayln v)) (displayln-twice "sent to real displayln") (mock? displayln) (module+ test (displayln-twice "sent to mock displayln") (mock? displayln) (mock? displayln-mock))) eval:2:0: displayln-mock: unbound identifier in module
context...:
#(170972 module) #(170973 module m 0) #(172413 module)
#(172414 module (m test) 0) #(172450 local) #(172451
intdef)
other binding...:
#<module-path-index:()>
#(170972 module) #(170973 module m 0) #(171008 macro)
#(172413 module)
#(172414 module (m test) 0)
in: displayln-mock
> (require 'm) require: unknown module
module name: #<resolved-module-path:'m>
> (require (submod 'm test)) require: unknown module
module name: #<resolved-module-path:(submod 'm test)>