Outdated egg!
This is an egg for CHICKEN 4, the unsupported old release. You're almost certainly looking for the CHICKEN 5 version of this egg, if it exists.
If it does not exist, there may be equivalent functionality provided by another egg; have a look at the egg index. Otherwise, please consider porting this egg to the current version of CHICKEN.
Missbehave
TOC »
Introduction
Missbehave is a toolkit that allows to you to bring behaviour driven development in the spirit of rspec, to your scheme of choice.
It is very much inspired and mostly modeled after the famous rspec-library.
Sources
You can find the egg sources at: https://bitbucket.org/certainty/missbehave
The name
As it has been asked on #chicken and it really can be misleading, here is why the name is spelled this way. It is intended to be a pun. (I guess not a good one, as i have to explain it)
It consists of the words miss where i mean error. And behave where i mean, erm, behave. So you may read as "C'mon miss, behave!". That's by the way also the reason why the cli is called behave.
So the two words together form "missbehave" which is intentionally close to "misbehave".
To be totally fair. I quite understand why this has been discussed, as i'm very aware of my limitions regarding english spelling.
Examples
(use missbehave missbehave-matchers missbehave-stubs miscmacros) (define (callee . args) 'called) (define (call-it n) (repeat n (callee))) (describe "Missbehave features" (describe "implicit subject" (subject-set! 42) (it (is > 10)) (it (is a number)) (it should (be 42))) (describe "Simple be matchers" (it "must be true" (expect #t (to (be true)))) (it "must be a string" (expect "hello" (to (be a string)))) (it "can use standard operators" (expect 3 (is > 0))) (it "can use predicates" (expect '() (is null?)))) (define (numbers ls) ls) (describe "Have" (it "can be used with a collection procedure" (expect '(1 2 3) (has 3 numbers))) (it "supports arbritary sugar" (expect "foo" (has 3 characters)))) (describe "Matches string" (it "checks if regex matches string" (expect '(: (+ digit)) (matches-string "1234"))) (it "checks the submatches" (expect '(: (+ digit) (submatch (+ any))) (matches-string "1234foo" with-matches: '((1 . "foo")))))) (describe "Pending" (it "is implicitly pending") (it "is explicitly pending" (pending) (expect '() (be a number)))) (describe "Procedure expectations" (context "Application-count" (it "checks application count" (expect (call-it 1) (call callee once))) (it "checks application count > 1" (expect (call-it 4) (call callee (4 times)))) (it "checks for no calls" (expect (+ 1 1) (call callee never)))) (context "Arguments" (it "checks arguments" (expect (callee 1 2) (call callee (with 1 2)))) (it "mixes arguments and application count" (expect (begin (callee 1 2) (callee 1 2)) (call callee (with 1 2) twice))))) (describe "Procedure stubs" (it "can stub return values" (stub! callee (returns 'not-called)) (expect (callee) (be 'not-called))) (it "provides temporary stubs" (let ((proc (lambda () 'test))) (expect (proc) (be 'test)) (with-stubs! ((proc (returns 'passed))) (expect (proc) (be 'passed))) (expect (proc) (be 'test))))))
Now invoke it with:
$ behave test-spec.scm
Produces the following output:
Missbehave features Procedure stubs It provides temporary stubs It can stub return values Procedure expectations Arguments It mixes arguments and application count It checks arguments Application-count It checks for no calls It checks application count > 1 It checks application count Pending [P] It is explicitly pending [P] It is implicitly pending Simple be matchers It can use predicates It can use standard operators It must be a string It must be true implicit subject It should (be a number) It should (be 42) Total: 15 Successful: 13 Pending: 2 Failures: 0
Authors
Api
Contexts
Contexts are a way to group your examples. You can use the the macro context and its alias describe to create them.
- (context context-name examples ...)syntax
Create a context with the name context-name.
- (context context-name (meta (tags ...)) examples ...)syntax
Create a context with name context-name and mark them with tags. This can be used to filter examples using the --tags command-line switch of behave.
- (context context-name (meta ((tag . value) ...)) examples ...)syntax
Create a context with name context-name and mark them with the key-value pairs. Those can be used to attach data and to filter them using the --tags command-line-switch of behave
Examples
(context "A simple context" (it "does nothing")) (context "A context with tags" (meta (long-running verbose)) (it "is pending")) (context "A context with value tags" (meta ((bug . "#402"))) (it "is pending"))
Examples
Examples allow you to specify a specific behaviour of your subject.
- (it description)syntax
Create a pending example with the description set to description
- (it should matcher)syntax
Creates an example that executes matcher on the current subject. See also subject-set!.
- (it description expectation ...)syntax
Creates an examples with the description set to description and the expectations.
(it "is pending") (it "succeeds" (expect #t))
Meta-Information
Metainformation can be used to mark certain examples or provide some form of addtional information. As a plus the behave-cli allows you to use those meta-information to filter certain examples.
- (it description (meta (tags ...)) expectations)syntax
Creates an example with expectations and tags.
- (it description (meta ((tag . value))) expectations ...)syntax
Create an example with expectations and key-value pairs, so that it can be filtered.
Examples
(it "has tags" (meta (some tag)) (expect #t)) (it "has more tags" (meta ((some . tag) (some . other))) (expect #t))
Expectations
Expectations are the bdd-way of stating assertions.
- (expect form)syntax
Create an expection that evaluates form and will fail if form evaluates to #f and pass otherwise.
(it "succeeds") (expect (string? "chickumber"))) (it "fails" ) (expect (> 2 3)))
- (expect subject to (call arguments ...))syntax
Creates an application-expectation. See also procedure-expections.
(define (reverse-list ls) (reverse ls)) (expect (reverse-list (list 1 2 3)) (call reverse))) (expect (reverse-list (list 1 2)) (call reverse once))) (expect (reverse-list (list 1 2)) (call reverse (with (list 1 2)))) (expect (reverse-list (list 1 2)) (call reverse (with (list 1 2)) once))
- (expect subject matcher)syntax
Create an expection on subject with matcher matcher.
(expect (list 1 2) (be a list)) (expect "foobar" (have 6 characters)) (expect 3.1 (be (close-to 3)))
Negative Expectations
If you want to state that a given subject should not have a certain behaviou, you can simply wrap the expect-form into a do-not form
- (do-not (expect ....))syntax
Creates an expection that fails if its inner expectation succeeds and vice versa.
Matchers
Matchers are the way to implement the checks for a given behaviour. They verify that a given subject behaves as expected.
- (matcher (check (subject) check-code) (message (form subject negate) message-code))syntax
This creates a fresh matcher object. You need to implement both the check and the message.
- check The check is a procedure that receives one argument, the subject. The subject is a promise so you need to force it if you want to retrieve the value.
- message This is the procedure that is invoked to generate the message. It receives three arguments
- form This is the quoted form that was passed to expect
- subject This is the subject. Again this is a promise so you need to force it to retrieve the actual value.
- negate Indicates if the check shall be negated. This is set to true if the expect-form has been wrapped into a (do-not) form.
(define (greater-than x) (matcher (check (subject) (> (force subject) x)) (message (form subject negate) (if negate (sprintf "Expected ~A to be less than or equal to ~A" (force subject) x) (sprintf "Expected ~A to be greater than ~A" (force subject) x))))) (expect 10 (be (greater-than 5)))
Builtin Matchers
Be
The be matcher is possibly the most used. It allows you to describe what a given subject should be. The be macro allows a fair few variations. I've listed all possible forms below
Aliases: is
- (be true)syntax
matches if subject is #t
- (be false)syntax
matches if subject is #f
- (be a type)syntax
matches if subject is of the specified type. It assumes that there is a procedure type? to check that.
(expect "string" (be a string)) (expect (list 1 2 3) (be a list))
- (be pred?)syntax
matches if pred? evaluates to #t when it is applied to subject
(expect 0 (be zero?))
- (be value)syntax
matches if current subject is equal to value in the sense of equal?.
- (be pred? value ...)syntax
This expands into something like (apply pred? (list subject value ...)). It provides a handy notation to write curried checks.
(expect 2 (be > 0)) (expect -100 (be <= 10))
Be-helpers
There are some procedures that enhance the possibilities of the be matcher
- close-to value #!key (delta 0.3)procedure
-
(expect 2 (be (close-to 1)) (expect 10/3 (be (close-to 3 delta: 0.4))
- any-of value #!rest more-valuesprocedure
-
(expect 2 (be (any-of 1 2 3 4))
- none-of value #!rest more-valuesprocedure
-
(expect 5 (be (none-of 1 2 3 4))
- list-including value #!rest more-valuesprocedure
-
(expect (list 1 2 3) (be (list-including 1 2))
match-string
This matcher can be used to describe the behaviour of regular expressions.
Aliases: matches-string
- match-string str #!key (with-matches #f)procedure
This succeeds if the regular expression represented by subject matches the string str. If with-matches is supplied, it is expected to be an alist holding the expected captures.
(expect '(: (+ space) (submatch (+ any))) (match-string " test" with-matches: '((1 . "test"))) (expect '(: (+ any)) (match-string "just a test"))
have
This matcher can be used to specify expectations on the amount of items in a collection.
Aliases: has
(expect "string" (has 6 chars)) (define (even-numbers ls) (filter even? ls)) (expect '(1 2 3 4 5) (has 2 even-numbers))
call
This matcher is used to express procedure-expectations. It allows you to state that a form is expected to call a procedure.
Aliases: calls
- (call proc once)syntax
matches if proc is called exactly once.
- (call proc twice)syntax
matches if proc is called twice
- (call proc never)syntax
matches if proc is never called.
- (call proc (n time))syntax
matches if proc is called n times.
- (call proc (with arg ...))syntax
matches if proc is called at least once with the given arguments.
- (call proc (with arg ...) amount-spec)syntax
matches if proc is called with the given arguments and matches the amount-spec which is one of the above (once never (n times)).
(define (foo) "foo") (define (i-call-foo) (foo)) (define (bar x y) "bar") (define (i-call-bar) (bar 1 2)) (expect (i-call-foo) (call foo once)) (expect (i-call-bar) (call bar (with 1 2) once))
raise
This matcher allows you to formulate expections about errors
- (raise error)syntax
Matches if subject raises errors.
- (raise (kind ...))syntax
Matches if subject raises an error and sets the kind-property at least to those specified.
(expect (error "test") (raise error))
Stubs
Missbehave provides a simple way to stub procedures. This is useful in cases where you want to control some of the procedures that interface, with the one you currently describe.
- (with-stubs! ((name stub) ... ) code ...)syntax
This form replaces the behavior of name with the stub code. Note that there is a (returns)-form which is a short-hand to create a procedure that returns the given value.
- returns value #!rest more-valuesprocedure
Creates a procedure that returns value. If you specify multiple value the procedure will return multiple values.
(define (return-3) 3) (with-stubs! ((return-3 (returns "not 3")) (printf "return-3 returns ~A~%" (return-3)))