I first heard about property testing at an erlang conference when I was in graduate school.  A guy from Volvo was giving a talk about something called property based testing. He described how they had this immensely complex piece of software that ran all of the subsystems in their cars, and how even just figuring out how to test it was insanely complicated and expensive.  How do you write a software test that ensures that when the driver hits the brake the braking subsystem does what it's supposed to do?  Does it work no matter what else the system is doing?  Can you be sure?  Property based testing had given them the ability to test the entire system, and discovered a huge number of bugs in the process - including one where you could lock up some critical system by engaging it at the same time you were turning up the radio.

Not all of us are writing safety critical software every day, but the problem space is similar.  Most pieces of software are pretty complicated and involve a lot of moving parts - an API layer, a database, some logic in the middle.  Writing good tests for any one piece of the puzzle is a challenge, but writing even halfway decent tests that actually cover the possible states of a complicated system is hard.  

Generally you test complex things by putting them in very specific states and then testing that they work in that state.  It's a good start, but like the man once said, no plan survives contact with the enemy.  The fact is that in the real world, it's often difficult and bordering on impossible to even describe all of the states your software can be in, let alone actually to actually enumerate those states so that you can test them.  

As a contrived example, imagine you have three moving parts - an API layer that receives requests, some business logic layer that processes them, and a data persistence layer that retrieves and stores data.  Pretend that each one of them can be in one of three states - that might be receiving requests vs waiting for a response for the API layer, or in a transaction vs. idle for your data layer.

Cool, that's 3 x 3 x 3 = 27 possible system states.  One or two more components with a similar number of states and you're talking hundreds of possibilities.  Traditional unit testing does not scale well here, and that's because it's not designed to.

Unit testing is really designed to test that in a specific circumstance, a specific piece of your system behaves as expected.  What I love about property testing is that it takes a different approach.  Property based testing tries to get your system into every possible state, and tests that once it's in that state, it behaves as expected.

It works by giving you a framework in which to describe what the possible inputs are to your system, and subsequently what you expect to be true about the outputs given those inputs.  Instead of being prescriptive about the specific data you use to test your code, it instead encourages you to think about the spectrum of possible data that your code needs to handle.  

As an incredibly simple example, imagine the following very simple function:

def double(x):
	return x * 2

A traditional unit test might look something like

def test_double(x):
	assert double(1) == 2

Whereas a property based test (using the excellent hypothesis library for python) would instead look like

from hypothesis import given
from hypothesis.strategies import integers

@given(integers)
def test_double(x):
	assert double(x) == x * 2

So I'm declaring that the function double should behave in a specific way given any integer, not just whatever integer I happened to choose for my test.  And this is way more powerful!  By encouraging me to think about what's possible instead of what's obvious, property based tests help me write better code.

It turns out that this pattern lets you do some really cool shit.  A slightly more complex example:

from hypothesis import given
from hypothesis.strategies import one_of, just, composite

period = one_of(just("am"), just("pm"))
hour = integers(min_value=1, max_value=12)
minute = integers(min_value=0, max_value=59)

@composite
def time(draw):
	hr = draw(hour)
	min = draw(minute)
	am_or_pm = draw(period)
	return "{}:{}{}".format(hr, min, am_or_pm)

@given(time)
def test_my_time_thing(some_time):
	assert check_time(some_time) == True

There's a little bit of boilerplate in there, but it should be pretty clear what's happening.  In just a few lines of code, this unit test is empowered to check all possible times.  

The moral of the property based testing story is that traditional unit tests are great for modeling your code.  You keep the data fixed, run it through the code, and make sure it worked.  Property based testing allows you to also model the data that your code will interact with in the wild.  It makes unit tests tell a fuller story, and on top of that encourages you to think about (and allows you to express!) what's really possible out there.