Open-source project
proper-testing/proper avatar
proper-testing/proper

PropEr makes Erlang code prove properties instead of enumerating cases

PropEr: a QuickCheck-inspired property-based testing tool for Erlang

918 stars165 forksErlangGPL-3.0

At a glance

What is it?
PropEr is a QuickCheck-inspired property-based testing tool for Erlang where you state a property about the input and output relation and let the tool generate increasingly complex inputs until the property breaks. Its input domain is expressed in the Erlang type language itself, and it ships a separate subsystem for testing stateful code.
Who is it for?
Adopt PropEr when you are writing Erlang and want to test a pure function or a state machine by stating what must always hold rather than by hand writing input and expected output pairs. Do not adopt it for property-based testing in another language, since the generators and the type integration are Erlang specific.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 11 days ago.
What is it written in?
Mainly Erlang, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • proper-testing/proper918 ★ · +0
Star history
Repository2026-10-222026-11-07
proper-testing/proper918918

0 Stars in the last 16 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Why enumerating test cases is the wrong shape for Erlang

The README starts with the traditional method and its two problems, and they are the reason this tool exists. Traditional testing involves writing a series of test inputs along with their corresponding expected outputs, then running the program with those inputs and observing whether it behaves as expected. It is simple and easy to automate, but writing test cases by hand is tedious and time consuming, and it is hard to know whether the test suite covers all aspects of the software under test. Property-based testing inverts that. The tester specifies only the generic structure of valid inputs for the program under test, plus the properties about the program's behaviour and the input-output relation that are expected to hold for every valid input. The tool then randomly produces progressively more complex valid inputs, applies them to the program while monitoring its execution, and checks that it behaves according to the supplied properties. The examples in the README are ordinary properties written in plain language. A program should accept any character string and convert all lowercase letters inside the string to uppercase. A program should accept any list of integers, and if the input list is at least four elements long it should return the fourth largest integer, otherwise it should throw an exception. Read that second example carefully. It states the domain, the behaviour and the boundary condition in one sentence, and it has no enumerated inputs at all. That is the entire value proposition. The audience is Erlang developers, and the focus is on the behaviour of pure functions, with a separate subsystem for stateful code on top.

Generators built from the Erlang type language

The part that makes PropEr more than a generic random data generator is its integration with Erlang's own type language. The README lists three consequences of that integration. Types expressed in the Erlang type language can be used instead of generators written in PropEr's own type system as input data specifications. Generators for abstract data types can be constructed automatically using the ADTs' API functions. And PropEr can test functions automatically, based solely on information provided in their specs. That third point is the strongest one and deserves unpacking. If a function already has a spec that describes what it accepts, PropEr can use those specs to drive the testing rather than requiring you to restate the domain in a second notation. For a code base that is disciplined about specs, that removes most of the work of writing a property test. The properties themselves are written as ordinary Erlang expressions, with the help of a few predefined macros, and the input domain of functions is specified through the use of a type system modelled closely after the type system of the language itself. For algebraic data types, the automatic construction of generators from the API functions means the test data matches the shape the type intends, including the recursive structures that hand written generators usually get wrong. The repository's examples directory shows the range in practice, with files for an ADT based stack, a labyrinth, a mastermind style game, a base64 example, and several that are explicitly state machines, among them car_fsm.erl, elevator_fsm.erl, ets_statem.erl and pdict_statem.erl.

Stateful code gets its own subsystem

Property-based testing of pure functions is the easy half. The README notes that on top of its focus on pure functions, PropEr is equipped with two library modules that can be used for testing stateful code. That is the hard half, because a stateful system needs a model of its expected behaviour to compare against, and it needs the sequence of operations to be generated rather than the final state to be checked in isolation. The examples directory is heavy on state machine cases for that reason. The car_fsm.erl, elevator_fsm.erl, ets_statem.erl and pdict_statem.erl examples cover different flavours of stateful behaviour, from a car whose gear and speed evolve to a system built on ETS tables and one built on the process dictionary. This is where the original authors split the work. The README credits the base PropEr system as written mainly by Manolis Papadakis, and the stateful code testing subsystem to Eirini Arvaniti, with Kostis Sagonas actively maintaining the code base since 2012. The copyright line reads 2010-2026 by Manolis Papadakis, Eirini Arvaniti, and Kostis Sagonas, which puts the age of the project at well over a decade. That is worth knowing when you are choosing a testing tool, because it means the generator library has been shaped by a lot of real Erlang.

Building it and putting it on the Erlang library path

The quickstart is a set of small steps. First get the sources, either a tagged version from the Tags list on GitHub or a clone of the current code base.

shell
git clone [email protected]:proper-testing/proper.git

Then compile. Simply running make builds PropEr. If you intend to change the code or submit a pull request, the README says you most likely want make test to run the unit tests and make dialyzer to also run dialyzer on the code base. To do both and build the documentation, issue a make all, which additionally needs the syntax_tools application and a recent version of EDoc. There is also a Homebrew route.

shell
brew install proper

Then the library path. The README gives two methods, the ERL_LIBS environment variable in your shell startup file.

shell
export ERL_LIBS=/full/path/to/proper

or a line in your .erlang resource file.

erlang
code:load_abs("/full/path/to/proper").

After that you add the include line to all source files that contain properties.

erlang
-include_lib("proper/include/proper.hrl").

and compile those source files, preferably with debug_info enabled. The Makefile shows how the build actually works. The default target is compile, which uses rebar3 and then symlinks the built ebin directory, and the all target is compile dialyzer doc test. The rebar3 version is pinned to 3.15.2, with a comment explaining that this is a safe version that still supports Erlang/OTP 20.x and 21.x and should be upgraded when support for those versions is dropped. There is also a rebar.config and a rebar.cmd for Windows.

Running one property, and the EUnit clash you will hit

A property is a function, and running it is one call.

erlang
proper:quickcheck(your_module:some_property()).

That is the whole interface for the common case. The README points at the tutorials and testing tips on the project's home page for getting started, and notes that the API documentation can be built from source with make doc. If you run properties from EUnit, two specific problems come up, and the README documents both. The first is a macro name collision. Both systems define a ?LET macro, and the fix is to include PropEr's header file before EUnit's, so that any instance of ?LET counts as a PropEr ?LET. The second is that EUnit captures standard output, so PropEr output is normally not visible when proper:quickcheck() is invoked from EUnit. The workaround is to pass the option {to_file, user}.

erlang
?assertEqual(true, proper:quickcheck(your_mod:some_prop(), [{to_file, user}])).

That makes PropEr properties visible even when invoked from EUnit, which matters because a property that fails quietly inside an EUnit run is worse than no test at all. The README also has a section on incompatibilities with QuviQ's QuickCheck, stating that PropEr's notation and output format has been kept quite similar. That comparison is the closest thing to an alternative in the documentation, and the difference is that PropEr is Erlang native, integrates with the Erlang type language, and is GPL licensed rather than commercial.

GPL version 3, a slow release cadence, and a still active project

The licence is GPL version 3 or later, as the README states and as the COPYING file at the root of the tree carries. The Makefile header repeats the terms, including the standard notice about the warranty. That is the single most consequential fact for an adopter outside the open source world. A permissive licence would let you use PropEr inside a proprietary product without ceremony. The GPL means that distributing a work linked to PropEr carries obligations, and that is a question for your legal counsel rather than for this article. The README also notes that PropEr is available on Hex PM, with a badge for it. On activity, the last push was on 2026-06-24 and the repository is not archived, so work continues. The releases are v1.5.0 from 2025-03-26, v1.4 from 2021-05-18 and v1.3 from 2018-07-25, so the current release line is a slow one, which is normal for a testing library whose API has been stable for years. The repository layout supports the development story. There is src/ for the code, test/ for the unit tests, examples/ for the reference properties, include/ for the header, doc/ for the documentation, scripts/, a .plt/ directory for the dialyzer base PLT, and a THANKS file. The dialyzer setup is worth one more look, because it is a quality practice that many Erlang projects skip. The dialyzer target depends on .plt/proper_plt and runs dialyzer with -Wunmatched_returns over the compiled ebin, so unmatched return values are treated as warnings in the project's own build.

Editorial conclusion

Adopt PropEr when you are writing Erlang and want to test a pure function or a state machine by stating what must always hold rather than by hand writing input and expected output pairs. Do not adopt it for property-based testing in another language, since the generators and the type integration are Erlang specific. Before you start, check that your build can run dialyzer and that you can include the PropEr header, and note that the tool is GPL version 3 or later, so linking it into a proprietary product needs a licence review.

Frequently asked questions

How do I install PropEr for Erlang?

Clone the repository and run make to build it, then add the base directory to the Erlang library path using the ERL_LIBS environment variable or a code:load_abs line in your .erlang file. Homebrew users can run brew install proper instead.

What is the difference between property-based testing and writing test cases?

With hand written test cases you supply specific inputs and expected outputs, which is tedious and leaves you unsure of coverage. With property-based testing you state only the structure of valid inputs and the properties that must hold for all of them, and the tool generates progressively more complex inputs to try to break them.

How does PropEr use the Erlang type language?

Types expressed in the Erlang type language can be used instead of PropEr's own generators, generators for ADTs can be constructed automatically from their API functions, and PropEr can test functions automatically based solely on the information in their specs.

How do I run a property from EUnit without losing the output?

EUnit captures standard output, so pass the {to_file, user} option to proper:quickcheck/2, for example ?assertEqual(true, proper:quickcheck(your_mod:some_prop(), [{to_file, user}])). You also need to include PropEr's header before EUnit's, because both define a ?LET macro.

What licence is PropEr released under?

The README states the program is distributed under the GNU General Public License, version 3 or later, with the details in the COPYING file. Copyright is held by Manolis Papadakis, Eirini Arvaniti and Kostis Sagonas.

Official sources

  1. License: GPL-3.0
  2. Project website
  3. proper-testing/proper on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/proper-testing-proper.svg)](https://hysenlabs.com/projects/proper-testing-proper)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/proper-testing-proper.svg)](https://hysenlabs.com/projects/proper-testing-proper)

Was this useful?