1[![Github Actions][github badge]][github]
2[![CodeCov][codecov badge]][codecov]
3[![Erlang Versions][erlang versions badge]][erlang]
4[![License][license badge]][license]
5[![Latest Release][release badge]][release]
6[![Hex PM][hex pm badge]][hex]
7[![Last Commit][commit badge]][commit]
8
9Contact information and license
10-------------------------------
11
12PropEr (PROPerty-based testing tool for ERlang) is a QuickCheck-inspired
13open-source property-based testing tool for Erlang, developed by Manolis
14Papadakis, Eirini Arvaniti, and Kostis Sagonas. The base PropEr system was
15written mainly by Manolis Papadakis, and the stateful code testing subsystem
16by Eirini Arvaniti. Kostis Sagonas has been actively maintaining its code
17base since 2012.
18
19You can reach PropEr's developers in the following ways:
20
21*   on the web: at [the project's home page](http://proper-testing.github.io)
22    or [the project's github page](https://github.com/proper-testing/proper)
23*   by email: take the tool's name (all lowercase), add a @ followed by
24    softlab dot ntua dot gr
25
26We welcome user contributions and feedback (comments, suggestions, feature
27requests, bug reports, patches, etc.).
28
29Copyright 2010-2021 by Manolis Papadakis, Eirini Arvaniti, and Kostis Sagonas.
30
31This program is distributed under the [GPL](http://www.gnu.org/licenses/gpl.html),
32version 3 or later. Please see the [COPYING][license] file for details.
33
34
35Introduction
36------------
37
38Traditional testing methodologies essentially involve software testers writing a
39series of test inputs for their programs, along with their corresponding
40expected outputs, then running the program with these inputs and observing
41whether it behaves as expected. This method of testing, while simple and easy to
42automate, suffers from a few problems, such as:
43
44*   Writing test cases by hand is tedious and time consuming.
45*   It is hard to know whether the test suite covers all aspects of the software
46    under test.
47
48Property-based testing is a novel approach to software testing, where the tester
49needs only specify the generic structure of valid inputs for the program under
50test, plus certain properties (regarding the program's behaviour and the
51input-output relation) which are expected to hold for every valid input.
52A property-based testing tool, when supplied with this information, should randomly
53produce progressively more complex valid inputs, then apply those inputs to the
54program while monitoring its execution, to ensure that it behaves according to
55its specification, as outlined in the supplied properties.
56
57Here are a few examples of simple properties a user may wish to test, expressed
58in natural language:
59
60*   The program should accept any character string and convert all lowercase
61    letters inside the string to uppercase.
62*   The program should accept any list of integers. If the input list is at
63    least 4 elements long, the program should return the 4th largest integer in
64    the list, else it should throw an exception.
65
66PropEr is such a property-based testing tool, designed to test programs written
67in the Erlang programming language. Its focus is on testing the behaviour of
68pure functions. On top of that, it is equipped with two library modules that can
69be used for testing stateful code. The input domain of functions is specified
70through the use of a type system, modeled closely after the type system of the
71language itself. Properties are written using Erlang expressions, with the help
72of a few predefined macros.
73
74PropEr is also tightly integrated with Erlang's type language:
75
76*   Types expressed in the Erlang type language can be used instead of
77    generators written in PropEr's own type system as input data specifications.
78*   Generators for ADTs can be constructed automatically using the ADTs' API
79    functions.
80*   PropEr can test functions automatically, based solely on information
81    provided in their specs.
82
83
84Quickstart guide
85----------------
86
87*   Obtain a copy of PropEr's sources. You can either get a tagged version of
88    the tool (look under `Tags` on github) or you can clone the current code
89    base:
90
91    ```shell
92    git clone git://github.com/proper-testing/proper.git
93    ```
94*   Compile PropEr: Simply run `make` if you just want to build PropEr.
95    If you want to do some changes to PropEr or submit some pull request you
96    most likely will want to issue a `make test` to run its unit tests and
97    a `make dialyzer` call to also run dialyzer on PropEr's code base.
98    To do the above but also build PropEr's documentation issue a `make all`
99    call; in that case, you are going to need the `syntax_tools` application
100    and a recent version of `EDoc`).
101*   If you are using [Homebrew](https://brew.sh), you can simply:
102
103    ```shell
104    brew install proper
105    ```
106    and continue following the instructions below.
107*   Add PropEr's base directory to your Erlang library path, using one of the
108    following methods:
109    1.   `ERL_LIBS` environment variable: Add the following line to your shell
110         startup file (`~/.bashrc` in the case of the Bash shell):
111
112         ```shell
113         export ERL_LIBS=/full/path/to/proper
114         ```
115    2.   Erlang resource file: Add the following line to your `~/.erlang` file:
116
117         ```erlang
118         code:load_abs("/full/path/to/proper").
119         ```
120*   Add the following include line to all source files that contain properties:
121
122    ```erlang
123    -include_lib("proper/include/proper.hrl").
124    ```
125
126*   Compile those source files, preferably with `debug_info` enabled.
127*   For each property, run:
128
129    ```erlang
130    proper:quickcheck(your_module:some_property()).
131    ```
132    See also the section common problems below if you want to run
133    PropEr from EUnit.
134
135
136Where to go from here
137---------------------
138
139To get started on using PropEr, see the tutorials and testing tips provided on
140[PropEr's home page](http://proper-testing.github.io). On the same site you can
141find a copy of PropEr's API documentation (you can also build this from source
142if you prefer, by running `make doc`), as well as links to more resources on
143property-based testing.
144
145
146Common problems
147---------------
148
149### Using PropEr in conjunction with EUnit
150
151The main issue is that both systems define a **`?LET`** macro. To avoid a
152potential clash, simply include PropEr's header file before EUnit's. That
153way, any instance of **`?LET`** will count as a PropEr **`?LET`**.
154
155Another issue is that [EUnit captures standard output][eunit stdout],
156so normally PropEr output is not visible when `proper:quickcheck()` is
157invoked from EUnit. You can work around this by passing the option
158`{to_file, user}` to `proper:quickcheck/2`. For example:
159```erlang
160?assertEqual(true, proper:quickcheck(your_mod:some_prop(), [{to_file, user}])).
161```
162This will make PropEr properties visible also when invoked from EUnit.
163
164
165Incompatibilities with QuviQ's QuickCheck
166-----------------------------------------
167
168PropEr's notation and output format has been kept quite similar to that of
169QuviQ's QuickCheck in order to ease the reuse of existing testing code written
170for that tool. However, incompatibilities are to be expected, since we never
171run or owned a copy of QuviQ's QuickCheck and the two programs probably bear
172little resemblance under the hood. Here we provide a nonexhaustive list of
173known incompatibilities:
174
175*   **`?SUCHTHATMAYBE`** behaves differently in PropEr.
176*   `proper_gen:pick/1` differs from `eqc_gen:pick/1` in return value format.
177*   PropEr handles `size` differently from QuickCheck.
178*   `proper:module/2` accepts options in the second argument instead of the
179    first; this is for consistency with other `module/2` functions in Erlang/OTP.
180
181All the above are from circa 2010. Most likely, there exist many more
182incompatibilities between the two tools by now.
183
184
185<!-- Links (alphabetically) -->
186[codecov]: https://codecov.io/gh/proper-testing/proper
187[commit]: https://github.com/proper-testing/proper/commit/HEAD
188[erlang]: http://www.erlang.org
189[eunit stdout]: http://erlang.org/doc/apps/eunit/chapter.html#Running_EUnit
190[hex]: https://hex.pm/packages/proper
191[license]: ./COPYING
192[release]: https://github.com/proper-testing/proper/releases/latest
193[github]: https://github.com/proper-testing/proper/actions
194
195<!-- Badges (alphabetically) -->
196[codecov badge]: https://codecov.io/gh/proper-testing/proper/branch/master/graph/badge.svg
197[commit badge]: https://img.shields.io/github/last-commit/proper-testing/proper.svg?style=flat-square
198[erlang versions badge]: https://img.shields.io/badge/erlang-20.0%20to%2024.0-blue.svg?style=flat-square
199[hex pm badge]: https://img.shields.io/hexpm/v/proper.svg?style=flat
200[license badge]: https://img.shields.io/github/license/proper-testing/proper.svg?style=flat-square
201[release badge]: https://img.shields.io/github/release/proper-testing/proper.svg?style=flat-square
202[github badge]: https://github.com/proper-testing/proper/workflows/CI/badge.svg
203