• Stars
    star
    125
  • Rank 286,335 (Top 6 %)
  • Language
    Clojure
  • Created about 11 years ago
  • Updated about 9 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

@reiddraper's test.check (née simple-check), made Clojure/ClojureScript-portable DEPRECATED

double-check Build Status

DEPRECATED

I strongly suggest migrating to use test.check, which now provides Clojure and ClojureScript APIs. Thanks to all contributors for helping with this stopgap until test.check made that transition.


double-check is a fork of @reiddraper's test.check (née simple-check) library, a property-based testing tool inspired by QuickCheck. The core idea of test.check (and thus, double-check) is that instead of enumerating expected input and output for unit tests, you write properties about your function that should hold true for all inputs. This lets you write concise, powerful tests.

Why a fork?

While test.check is dedicated to remaining a Clojure-only API (at least for now?) double-check is written using cljx, and thus provides an API that is portable between Clojure and ClojureScript. This approach has already uncovered significant bugs in ClojureScript itself, and can do the same for your programs.

Please note that this fork:

  1. ...always tracks test.check as closely as possible, with the only divergences being those necessary to ensure an API portable between Clojure and ClojureScript.
  2. ...is not a rewrite. The move to cljx yields minimal changes compared to the test.check baseline; 100% of the core logic flows from it. There's nothing novel here.
  3. ...is not hostile in any way to test.check, @reiddraper, etc. (It's actually @reiddraper-approved! :-P) It exists solely to make it possible to apply test.check's testing approach to ClojureScript libraries and applications, not to supplant or compete with test.check. In particular, the core abstractions and generator/shrinking implementation defined in test.check are considered canonical. If test.check eventually provides equivalent functionality for the ClojureScript side of the house, this project will be shuttered.
  4. ...does not make any guarantees about 100% API compatibility with test.check, though it is based upon and tracks it. i.e. you should not expect to be able to move from test.check to double-check (or vice versa) in a Clojure project with no changes. Except for the (slightly) different namespaces, no changes are known to be required right now, but that may change to maximize runtime target portability.
  5. ...retains the clojure.test.check.* namespace structure, despite the name of this repo. This is to make tracking easier, and to allow users to share/port examples and usage of each package back and forth with a minimum of pain.

A word on versioning: version numbers will track test.check version numbers as well, using a suffixed classifier (e.g. 0.1.2 turns into 0.1.2-1) to indicate local changes made in between test.check releases. SNAPSHOT version numbers will be the same as test.check's.

Releases and Dependency Information

Leiningen

Add this to your :dependencies:

[com.cemerick/double-check "0.6.1"]

Maven

<dependency>
  <groupId>com.cemerick</groupId>
  <artifactId>double-check</artifactId>
  <version>0.6.1</version>
</dependency>

Documentation

Migrating from simple-check or test.check

In order to migrate from simple-check or test.check to double-check, you'll need to do two things:

  • Update project.clj

    In your project.clj replace [reiddraper/simple-check "$VERSION"] or [org.clojure/test.check "$VERSION"] with [com.cemerick/double-check "$LATEST_VERSION_HERE"] (note: your version numbers may be different).

  • Update namespace declarations

    Update your namespaces: simple-check.core becomes clojure.test.check (note the dropping of 'core'). For all other things, just replace simple-check with clojure.test.check. Let's make it easy:

    find test -name '*.clj' -print0 | xargs -0 sed -i.bak \
    -e 's/simple-check.core/clojure.test.check/' \
    -e 's/simple-check/clojure.test.check/'

    Review the updates.

Examples

Let's say we're testing a sort function. We want to check that that our sort function is idempotent, that is, applying sort twice should be equivalent to applying it once: (= (sort a) (sort (sort a))). Let's write a quick test to make sure this is the case:

(ns double-check.demos
  (:require [cemerick.double-check.core :as sc]
            [cemerick.double-check.generators :as gen]
            [cemerick.double-check.properties :as prop :include-macros true]))

(def sort-idempotent-prop
  (prop/for-all [v (gen/vector gen/int)]
    (= (sort v) (sort (sort v)))))

(sc/quick-check 100 sort-idempotent-prop)
;; => {:result true, :num-tests 100, :seed 1382488326530}

In prose, this test reads: for all vectors of integers, v, sorting v is equal to sorting v twice.

What happens if our test fails? test.check will try and find 'smaller' input that still fails. This process is called shrinking. Let's see it in action:

(def prop-sorted-first-less-than-last
  (prop/for-all [v (gen/not-empty (gen/vector gen/int))]
    (let [s (sort v)]
      (< (first s) (last s)))))

(sc/quick-check 100 prop-sorted-first-less-than-last)
;; => {:result false, :failing-size 0, :num-tests 1, :fail [[3]],
       :shrunk {:total-nodes-visited 5, :depth 2, :result false,
                :smallest [[0]]}}

This test claims that the first element of a sorted vector should be less-than the last. Of course, this isn't true: the test fails with input [3], which gets shrunk down to [0], as seen in the output above. As your test functions require more sophisticated input, shrinking becomes critical to being able to understand exactly why a random test failed. To see how powerful shrinking is, let's come up with a contrived example: a function that fails if its passed a sequence that contains the number 42:

(def prop-no-42
  (prop/for-all [v (gen/vector gen/int)]
    (not (some #{42} v))))

(sc/quick-check 100 prop-no-42)
;; => {:result false,
       :failing-size 45,
       :num-tests 46,
       :fail [[10 1 28 40 11 -33 42 -42 39 -13 13 -44 -36 11 27 -42 4 21 -39]],
       :shrunk {:total-nodes-visited 38,
                :depth 18,
                :result false,
                :smallest [[42]]}}

We see that the test failed on a rather large vector, as seen in the :fail key. But then test.check was able to shrink the input down to [42], as seen in the keys [:shrunk :smallest].

To learn more, check out the documentation links.

clojure.test Integration

The clojure.test.check.clojure-test/defspec macro allows you to succinctly write properties that run under clojure.test (or clojurescript.test, as appropriate). For example:

(defspec first-element-is-min-after-sorting ;; the name of the test
         100 ;; the number of iterations for test.check to test
         (prop/for-all [v (gen/not-empty (gen/vector gen/int))]
           (= (apply min v)
              (first (sort v)))))

This defines a standard clojure.test / clojurescript.test test, which can be invoked directly to run only it. Or, you can run all of the tests in a namespace or the entire environment with the test-ns and run-all-tests utility functions in clojure.test and clojurescript.test.

See more examples in core_test.clj.

Release Notes

Release notes for each version are available in CHANGELOG.markdown. Changes that are specific to double-check (i.e. that don't flow from upstream changes in test.check) are noted as such.

See also...

Other implementations

Papers

Contributing

We can not accept pull requests. Please see CONTRIBUTING.md for details.

License

Copyright © 2013 Reid Draper and other contributors

Distributed under the Eclipse Public License, the same as Clojure.

More Repositories

1

jsdifflib

A javascript library for diffing text and generating corresponding HTML views
JavaScript
1,452
star
2

friend

An extensible authentication and authorization library for Clojure Ring web applications and services.
Clojure
1,157
star
3

austin

The ClojureScript browser-REPL rebuilt stronger, faster, easier.
Clojure
511
star
4

url

Makes working with URLs in Clojure and ClojureScript easy
Clojure
249
star
5

clojure-type-selection-flowchart

Flowchart for choosing the right Clojure type definition form
235
star
6

clojurescript.test

A maximal port of `clojure.test` to ClojureScript. DEPRECATED
Clojure
166
star
7

bandalore

A Clojure client library for Amazon's Simple Queue Service (SQS)
Clojure
77
star
8

nrepl-python-client

A Python client for nREPL, the Clojure network REPL
Python
49
star
9

friend-demo

An über-demo of most (eventually, all) that Friend has to offer.
Clojure
37
star
10

clojure-web-deploy-conj

A sample Clojure web application project with support for deployment via pallet and jclouds, as presented at the first Clojure Conj in October, 2010.
Clojure
29
star
11

pprng

portable pseudo-random number generators for Clojure and ClojureScript DEPRECATED
HTML
26
star
12

raposo

25
star
13

stopthatrightnow

HTML
12
star
14

ancap-news

A Chrome/Firefox extension to help bring out hacker news' true colors
JavaScript
11
star
15

yonder

Go eval this Clojure[Script] over there.
Clojure
8
star
16

silly-shootout

Shell
7
star
17

immutant-aws

WIP WIP WIP — automating AMI baking + vagrant usage of clustered immutant
Shell
5
star
18

mostly-lazy

Clojure
5
star
19

cemerick-mvn-repo

Chas Emerick's micro-mvn-repository
4
star
20

s3-photo-archiver

archival storage of photo and video media in AWS S3
Java
3
star
21

bollocks

2
star
22

.emacs.d

Portable emacs configuration file.
Emacs Lisp
2
star
23

Lemerick

2
star
24

this-plt-life

a little "script" for downloading all the gifs from http://this-plt-life.tumblr.com/
Clojure
2
star
25

utc-dates

A simple date formatting/parsing library.
Clojure
1
star
26

clutch-clojurescript

1
star
27

ikvm-mono-exit-hang

Reproduction of bug described here: https://sourceforge.net/mailarchive/forum.php?thread_name=B75FBFED-D6C4-4E19-BD7E-B4F331F3C3E9%40snowtide.com&forum_name=ikvm-developers
C#
1
star