The cl-mock Reference Manual

Table of Contents

Next: , Previous: , Up: (dir)   [Contents][Index]

The cl-mock Reference Manual

This is the cl-mock Reference Manual, version 1.0.0, generated automatically by Declt version 2.3 "Robert April" on Wed Mar 14 03:25:51 2018 GMT+0.


Next: , Previous: , Up: Top   [Contents][Index]

1 Introduction

-- mode: markdown; coding: utf-8-unix; --

CL-MOCK - Mocking functions.

Copyright (C) 2013-16 Olof-Joachim Frahm

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Working, but unfinished.

Build Status

Portable to at least ABCL, Allegro CL (with one problem with inlining settings), SBCL, CCL and CLISP. CMUCL possibly, but not tested on Travis CI. ECL fails on Travis CI (OPTIMA fails there as well), but runs successfully on my own machine, so YMMV. See the detailed reports at https://travis-ci.org/Ferada/cl-mock for more information and CL-TRAVIS, and .travis.yml for the setup.

INTRODUCTION

This small library provides a way to replace the actual implementation of either regular or generic functions with mocks. On the one hand how to integrate this facility with a testing library is up to the user; the tests for the library are written in FIVEAM though, so most examples will take that into account. On the other hand writing interactions for mocks usually relies on a bit of pattern matching, therefore the regular CL-MOCK package relies on OPTIMA to provide that facility instead of deferring to the user. Should this be a concern a reduced system definition is available as CL-MOCK-BASIC, which excludes the definition of ANSWER and the dependency on OPTIMA.

Since it is pretty easy to just roll something like this on your own, the main purpose is to develop a nice (lispy, declarative) syntax to keep your tests readable and maintainable.

Some parts may be used independently of the testing facilities, e.g. dynamic FLET may be of general interest.

MOCKING REGULAR FUNCTIONS

Let's say we have a function FOO, then we can replace it for testing by establishing a new mocking context and then specifying how the new function should behave (see below in UTILITIES for a more primitive dynamic function rebinding):

> (declaim (notinline foo bar))
> (defun foo () 'foo)
> (defun bar (&rest args)
>   (declare (ignore args))
>   'bar)
> (with-mocks ()
>   (answer (foo 1) 42)
>   (answer foo 23)
>   (values
>    (eql 42 (foo 1))
>    (eql 23 (foo 'bar))))
> => T T

The ANSWER macro has pattern matching (see OPTIMA) integrated. Therefore something like the following will now work as expected:

> (with-mocks ()
>   (answer (foo x) (format T "Hello, ~A!" x))
>   (foo "world"))
> => "Hello, world!"

If you don't like ANSWER as it is, you can still use IF-CALLED directly. Note however that unless UNHANDLED is called, the function always matches and the return value is directly returned again:

> (with-mocks ()
>   (if-called 'foo (lambda (x)
>                     (unhandled)
>                     (error "Not executed!")))
>   (if-called 'foo (lambda (x) (format T "Hello, ~A!" x)))
>   (foo "world"))
> => "Hello, world!"

Be especially careful to handle all given arguments, otherwise the function call will fail and that error is propagated upwards.

IF-CALLED also has another option to push a binding to the front of the list, which (as of now) isn't available via ANSWER (and should be treated as subject to change anyway).

Should you wish to run the previously defined function, use the function CALL-PREVIOUS. If no arguments are passed it will use the current arguments from *ARGUMENTS*, if any. Otherwise it will be called with the passed arguments instead. For cases where explicitely calling it with no arguments is necessary, using (funcall *previous*) is still possible as well.

> (with-mocks ()
>   (answer foo `(was originally ,(funcall *previous*)))
>   (answer bar `(was originally ,(call-previous)))
>   (values
>    (foo "hello")
>    (bar "hello")))
> => (WAS ORIGINALLY FOO) (WAS ORIGINALLY BAR)

The function INVOCATIONS may be used to retrieve all recorded invocations of mocks (so far); the optional argument can be used to filter for a particular name:

> (with-mocks ()
>   (answer foo)
>   (foo "hello")
>   (foo "world")
>   (bar "test")
>   (invocations 'foo))
> => ((FOO "hello")
>     (FOO "world"))

Currently there are no further predicates to check these values, this is however an area of investigation, so presumably either a macro like FIVEAMs IS, or regular predicates could appear in this place.

EXAMPLES

The following examples may give a better impression.

Here we test a particular ECLASTIC method, GET*. In order to replace the HTTP call with a supplied value, we use ANSWER with HTTP-REQUEST and return a pre-filled stream. Afterwards both the number of INVOCATIONS and the actual returned values are checked.

(use-package '(#:cl-mock #:fiveam #:eclastic #:drakma #:puri))

(def-test search.empty ()
  (let* ((events (make-instance '<type> :type "document" :index "index"
                                        :host "localhost" :port 9292))
         (text "{\"took\":3,\"timed_out\":false,\"_shards\":{\"total\":5,\
\"successful\":5,\"failed\":0},\"hits\":{\"total\":123,\"max_score\":1.0,\
\"hits\":[{\"_index\":\"index\",\"_type\":\"document\",\"_id\":\"12345\",\
\"_score\":1.0,\"_source\":{\"test\": \"Hello, World!\"}}]}}")
         (stream (make-string-input-stream text)))
    (with-mocks ()
      (answer http-request
        (values stream 200 NIL
                (parse-uri "http://localhost:9292/index/document/_search")
                stream NIL "OK"))
      (let ((values (multiple-value-list
                     (get* events (new-search NIL)))))
        (is (eql 1 (length (invocations))))
        (is (eql 1 (length (car values))))
        (is-true (typep (caar values) '<document>))
        (is (equal (cdr values)
                   '(NIL (:hits 123
                          :shards (:total 5 :failed 0 :successful 5)
                          :timed-out NIL :took 3))))))))

Of course, running this should produce no errors:

> (run! 'search.empty)
>
> Running test SEARCH.EMPTY ....
> Did 4 checks.
>    Pass: 4 (100%)
>    Skip: 0 ( 0%)
>    Fail: 0 ( 0%)
>
> => NIL

UTILITIES

DFLET dynamically rebinds functions similar to FLET:

> (defun foo () 42)
> (defun bar () (foo))
> (bar)
> => 42
> (dflet ((foo () 23))
>   (bar))
> => 23
> (OR) => 42, if FOO was inlined

The caveat is that this might not work on certain optimisation settings, including inlining. That trade-off seems acceptable; it would be nice if a warning could be issued depending on the current optimisation settings, however that is particularly implementation dependent, so lack of a warning won't indicate a working environment.

The underlying function PROGF may be used as well similarly to the standard PROG:

> (progf '(foo) (list (lambda () 23))
>   (bar))
> => 23
> (OR) => 42, if FOO was inlined

Next: , Previous: , Up: Top   [Contents][Index]

2 Systems

The main system appears first, followed by any subsystem dependency.


Next: , Previous: , Up: Systems   [Contents][Index]

2.1 cl-mock

Author

Olof-Joachim Frahm <olof@macrolet.net>

License

Simplified BSD License

Description

Mocking library

Long Description

Mocking library to test plain functions (extended version).

Version

1.0.0

Dependencies
Source

cl-mock.asd (file)

Component

src (module)


Previous: , Up: Systems   [Contents][Index]

2.2 cl-mock-basic

Author

Olof-Joachim Frahm <olof@macrolet.net>

License

Simplified BSD License

Description

Mocking library

Long Description

Mocking library to test plain functions.

Version

1.0.0

Dependencies
Source

cl-mock-basic.asd (file)

Components

Next: , Previous: , Up: Top   [Contents][Index]

3 Modules

Modules are listed depth-first from the system components tree.


Next: , Previous: , Up: Modules   [Contents][Index]

3.1 cl-mock/src

Parent

cl-mock (system)

Location

src/

Component

facade.lisp (file)


Previous: , Up: Modules   [Contents][Index]

3.2 cl-mock-basic/src

Dependency

readme.md (file)

Parent

cl-mock-basic (system)

Location

src/

Components

Next: , Previous: , Up: Top   [Contents][Index]

4 Files

Files are sorted by type and then listed depth-first from the systems components trees.


Next: , Previous: , Up: Files   [Contents][Index]

4.1 Lisp


Next: , Previous: , Up: Lisp files   [Contents][Index]

4.1.1 cl-mock.asd

Location

cl-mock.asd

Systems

cl-mock (system)


Next: , Previous: , Up: Lisp files   [Contents][Index]

4.1.2 cl-mock-basic.asd

Location

cl-mock-basic.asd

Systems

cl-mock-basic (system)


Next: , Previous: , Up: Lisp files   [Contents][Index]

4.1.3 cl-mock/src/facade.lisp

Parent

src (module)

Location

src/facade.lisp

Exported Definitions

answer (macro)

Internal Definitions

true (function)


Next: , Previous: , Up: Lisp files   [Contents][Index]

4.1.4 cl-mock-basic/src/package.lisp

Parent

src (module)

Location

src/package.lisp

Packages

cl-mock


Next: , Previous: , Up: Lisp files   [Contents][Index]

4.1.5 cl-mock-basic/src/functions.lisp

Parent

src (module)

Location

src/functions.lisp

Exported Definitions

Previous: , Up: Lisp files   [Contents][Index]

4.1.6 cl-mock-basic/src/mock.lisp

Parent

src (module)

Location

src/mock.lisp

Exported Definitions
Internal Definitions

Previous: , Up: Files   [Contents][Index]

4.2 Other


Previous: , Up: Other files   [Contents][Index]

4.2.1 cl-mock-basic/README.md

Parent

cl-mock-basic (system)

Location

README.md


Next: , Previous: , Up: Top   [Contents][Index]

5 Packages

Packages are listed by definition order.


Previous: , Up: Packages   [Contents][Index]

5.1 cl-mock

Source

package.lisp (file)

Use List
Exported Definitions
Internal Definitions

Next: , Previous: , Up: Top   [Contents][Index]

6 Definitions

Definitions are sorted by export status, category, package, and then by lexicographic order.


Next: , Previous: , Up: Definitions   [Contents][Index]

6.1 Exported definitions


Next: , Previous: , Up: Exported definitions   [Contents][Index]

6.1.1 Special variables

Special Variable: *arguments*
Package

cl-mock

Source

mock.lisp (file)

Special Variable: *previous*
Package

cl-mock

Source

mock.lisp (file)


Next: , Previous: , Up: Exported definitions   [Contents][Index]

6.1.2 Macros

Macro: answer CALL &body FORMS
Package

cl-mock

Source

facade.lisp (file)

Macro: dflet (&rest DEFINITIONS) &body BODY

Like FLET, but dynamically sets the FDEFINITIONS during the duration of the BODY.

Package

cl-mock

Source

functions.lisp (file)

Macro: progf FUNCTIONS VALUES &body BODY

Like PROGV, but for FUNCTIONS.

Package

cl-mock

Source

functions.lisp (file)

Macro: with-mocks (&key RECORDP) &body BODY

Execute BODY in a new mocking context. Invocations will be recorded if RECORDP is set (default true).

Package

cl-mock

Source

mock.lisp (file)


Previous: , Up: Exported definitions   [Contents][Index]

6.1.3 Functions

Function: call-previous &rest ARGS

Invokes the previous binding either with the current arguments or with the given ones. Use *PREVIOUS*/*ARGUMENTS* directly in edge cases.

Package

cl-mock

Source

mock.lisp (file)

Function: call-with-function-bindings FUNCTIONS VALUES FUNCTION &optional PREVIOUS

Calls FUNCTION while temporarily binding all FUNCTIONS with the given names to VALUES. See PROGF and PROGV. If PREVIOUS is set, it has to be the list of original values for each function.

Package

cl-mock

Source

functions.lisp (file)

Function: call-with-mocks FUNCTION &key (RECORDP *RECORDP*)

Call FUNCTION with a new mocking context. Invocations will be recorded if RECORDP is set (default true).

Package

cl-mock

Source

mock.lisp (file)

Function: if-called NAME FUNCTION &key AT-START

Registers a new binding, which should return true if it handled the invocation. If AT-START is set, the binding is put at the start of the bindings list instead. Calls REGISTER-MOCK automatically.

Package

cl-mock

Source

mock.lisp (file)

Function: invocations &optional NAME
Package

cl-mock

Source

mock.lisp (file)

Function: maybe-fdefinition NAME

If NAME is FBOUNDP, return its FDEFINITION, else NIL.

Package

cl-mock

Source

functions.lisp (file)

Function: register-mock NAME

Registers a mocked function under NAME. The mocked function will return no values. See IF-CALLED to add some behaviour to it.

Package

cl-mock

Source

mock.lisp (file)

Function: set-fdefinition NAME VALUE

FUNCALLABLE expansion of (SETF (FDEFINITION NAME) VALUE).

Package

cl-mock

Source

functions.lisp (file)

Function: set-or-unbind-fdefinition NAME VALUE

If VALUE is true, set the FDEFINITION of NAME to it, else FMAKUNBOUND it completely.

Package

cl-mock

Source

functions.lisp (file)

Function: unhandled ()
Package

cl-mock

Source

mock.lisp (file)


Previous: , Up: Definitions   [Contents][Index]

6.2 Internal definitions


Next: , Previous: , Up: Internal definitions   [Contents][Index]

6.2.1 Special variables

Special Variable: *invocations*
Package

cl-mock

Source

mock.lisp (file)

Special Variable: *mock-bindings*
Package

cl-mock

Source

mock.lisp (file)

Special Variable: *recordp*
Package

cl-mock

Source

mock.lisp (file)


Previous: , Up: Internal definitions   [Contents][Index]

6.2.2 Functions

Function: find-and-invoke-mock BINDING *ARGUMENTS*

Looks for a compatible mock (i.e. calls the TEST until one returns true) and executes it. If no mock was found, no values are returned instead.

Package

cl-mock

Source

mock.lisp (file)

Function: record-invocation RECORD &aux RECORD
Package

cl-mock

Source

mock.lisp (file)

Function: true &rest ARGUMENTS
Package

cl-mock

Source

facade.lisp (file)


Previous: , Up: Top   [Contents][Index]

Appendix A Indexes


Next: , Previous: , Up: Indexes   [Contents][Index]

A.1 Concepts

Jump to:   C   F   L   M   O  
Index Entry  Section

C
cl-mock-basic.asd: The cl-mock-basic<dot>asd file
cl-mock-basic/README.md: The cl-mock-basic/readme<dot>md file
cl-mock-basic/src: The cl-mock-basic/src module
cl-mock-basic/src/functions.lisp: The cl-mock-basic/src/functions<dot>lisp file
cl-mock-basic/src/mock.lisp: The cl-mock-basic/src/mock<dot>lisp file
cl-mock-basic/src/package.lisp: The cl-mock-basic/src/package<dot>lisp file
cl-mock.asd: The cl-mock<dot>asd file
cl-mock/src: The cl-mock/src module
cl-mock/src/facade.lisp: The cl-mock/src/facade<dot>lisp file

F
File, Lisp, cl-mock-basic.asd: The cl-mock-basic<dot>asd file
File, Lisp, cl-mock-basic/src/functions.lisp: The cl-mock-basic/src/functions<dot>lisp file
File, Lisp, cl-mock-basic/src/mock.lisp: The cl-mock-basic/src/mock<dot>lisp file
File, Lisp, cl-mock-basic/src/package.lisp: The cl-mock-basic/src/package<dot>lisp file
File, Lisp, cl-mock.asd: The cl-mock<dot>asd file
File, Lisp, cl-mock/src/facade.lisp: The cl-mock/src/facade<dot>lisp file
File, other, cl-mock-basic/README.md: The cl-mock-basic/readme<dot>md file

L
Lisp File, cl-mock-basic.asd: The cl-mock-basic<dot>asd file
Lisp File, cl-mock-basic/src/functions.lisp: The cl-mock-basic/src/functions<dot>lisp file
Lisp File, cl-mock-basic/src/mock.lisp: The cl-mock-basic/src/mock<dot>lisp file
Lisp File, cl-mock-basic/src/package.lisp: The cl-mock-basic/src/package<dot>lisp file
Lisp File, cl-mock.asd: The cl-mock<dot>asd file
Lisp File, cl-mock/src/facade.lisp: The cl-mock/src/facade<dot>lisp file

M
Module, cl-mock-basic/src: The cl-mock-basic/src module
Module, cl-mock/src: The cl-mock/src module

O
Other File, cl-mock-basic/README.md: The cl-mock-basic/readme<dot>md file

Jump to:   C   F   L   M   O  

Next: , Previous: , Up: Indexes   [Contents][Index]

A.2 Functions

Jump to:   A   C   D   F   I   M   P   R   S   T   U   W  
Index Entry  Section

A
answer: Exported macros

C
call-previous: Exported functions
call-with-function-bindings: Exported functions
call-with-mocks: Exported functions

D
dflet: Exported macros

F
find-and-invoke-mock: Internal functions
Function, call-previous: Exported functions
Function, call-with-function-bindings: Exported functions
Function, call-with-mocks: Exported functions
Function, find-and-invoke-mock: Internal functions
Function, if-called: Exported functions
Function, invocations: Exported functions
Function, maybe-fdefinition: Exported functions
Function, record-invocation: Internal functions
Function, register-mock: Exported functions
Function, set-fdefinition: Exported functions
Function, set-or-unbind-fdefinition: Exported functions
Function, true: Internal functions
Function, unhandled: Exported functions

I
if-called: Exported functions
invocations: Exported functions

M
Macro, answer: Exported macros
Macro, dflet: Exported macros
Macro, progf: Exported macros
Macro, with-mocks: Exported macros
maybe-fdefinition: Exported functions

P
progf: Exported macros

R
record-invocation: Internal functions
register-mock: Exported functions

S
set-fdefinition: Exported functions
set-or-unbind-fdefinition: Exported functions

T
true: Internal functions

U
unhandled: Exported functions

W
with-mocks: Exported macros

Jump to:   A   C   D   F   I   M   P   R   S   T   U   W  

Next: , Previous: , Up: Indexes   [Contents][Index]

A.3 Variables

Jump to:   *  
S  
Index Entry  Section

*
*arguments*: Exported special variables
*invocations*: Internal special variables
*mock-bindings*: Internal special variables
*previous*: Exported special variables
*recordp*: Internal special variables

S
Special Variable, *arguments*: Exported special variables
Special Variable, *invocations*: Internal special variables
Special Variable, *mock-bindings*: Internal special variables
Special Variable, *previous*: Exported special variables
Special Variable, *recordp*: Internal special variables

Jump to:   *  
S  

Previous: , Up: Indexes   [Contents][Index]

A.4 Data types

Jump to:   C   P   S  
Index Entry  Section

C
cl-mock: The cl-mock system
cl-mock: The cl-mock package
cl-mock-basic: The cl-mock-basic system

P
Package, cl-mock: The cl-mock package

S
System, cl-mock: The cl-mock system
System, cl-mock-basic: The cl-mock-basic system

Jump to:   C   P   S