I wrote some property-based tests for a parsing library. Eventually one of the tests for case-insensitive parsing failed... because it hit the letter "DŽ" which has upper, lower and title-case. The funny thing is that the parsing library was correct and it was the test property that was wrong—but I still learned about an edge case I had never considered! This has been a common pattern for "simpler" property-based test…
Why Property Testing Finds Bugs Unit Testing Does Not (2021)
21–30 of 90 posts
Re: Why Property Testing Finds Bugs Unit Testing Does Not (2021)
#22For then it's not clear how would one derive the answer from the generated inputs, that is what code is for.
But PBT can be great for pruning out crashes you don't expect while parsing.
Re: Why Property Testing Finds Bugs Unit Testing Does Not (2021)
#23I independently discovered PBT when I was a junior, and suggested we use it. My coworkers rejected it because tests should be predictable, and it's the programmer's job to pick the edge cases.
It seems to be almost totally forgotten, since the only link I could find is an excerpt from a PalmOS programming book:
https://www.oreilly.com/library/view/palm-programming-the/15...
Re: Why Property Testing Finds Bugs Unit Testing Does Not (2021)
#24I don't find this to be true at all. Most bugs I find are business scenarios that I didn't consider or mismatches in API expectations etc. Rarely is a bug for me coming from not considering edge cases of min and maximum values for integers, floats etc.
Re: Why Property Testing Finds Bugs Unit Testing Does Not (2021)
#25Why are we even testing to begin with, and not using theorem provers like lean to prove without any doubt that our commutative function is indeed commutative?
Re: Why Property Testing Finds Bugs Unit Testing Does Not (2021)
#26I wrote some property-based tests for a parsing library. Eventually one of the tests for case-insensitive parsing failed... because it hit the letter "DŽ" which has upper, lower and title-case. The funny thing is that the parsing library was correct and it was the test property that was wrong—but I still learned about an edge case I had never considered! This has been a common pattern for "simpler" property-based test…
That's Unicode, which has a whole section of hell dedicated to it.
Re: Why Property Testing Finds Bugs Unit Testing Does Not (2021)
#27Unfortunately it ends before it gets to the good stuff. It has me interested that maybe PBT can find some bugs that unit testing wouldn't - however I'm not sure how to write a PBT that would catch those bugs. The obvious tests that drive PBT advocates to drink are not interesting - unit tests will catch all the errors and because there is no randomness they will catch the errors faster in general. However how do I wr…
Yeah, for simple nearly mathematical functions it's quite clear how to do it. I find it hard to extend this to more business-focused inputs
It found so many bugs: file corruption, crashes, memory leaks, pathological performance issues. The kind of issues that standard unit testing doesn't find.
Re: Why Property Testing Finds Bugs Unit Testing Does Not (2021)
#28Why are we even testing to begin with, and not using theorem provers like lean to prove without any doubt that our commutative function is indeed commutative?
Proving code is only as good as the requirements which are often garbage - the customer often doesn't know what they even want. Even if you put in effort, requirements as the proof needs are often very abstract from the customer requirements and so your program can be proved but still be wrong because it doesn't do what the customer really wanted. In any complex program is a reasonable to state that several requirements are wrong and thus even if your prove your code correct it will be wrong. Often the problem itself cannot even be formally defined - a spell checker cannot be proved correct because human languages are not formally defined, not that you can't prove one, just that whatever you prove will be wrong.
Many systems are very complex. You can (should!) prove simple algorithms, but put everything together and a proof is not something we can do at all. There are too many halting problems like things in large programs.
Tests solve some of the above problems: They can (do not confuse with what they do!) be a simple example of "yes when inputs are exactly x,y,z then I expect that result". A bunch of simple examples that make sense can often be close enough.
We do a lot more theorem proving than most people realize. Types which many languages have are a form of formal proof. They don't cover everything, but even in C++ they cover a lot of issues.
I think the best answer is a combination: prove the things we know how to prove, and test the rest and hope that between the two we have covered enough to prevent bugs.
Re: Why Property Testing Finds Bugs Unit Testing Does Not (2021)
#29Earlier quoted context omitted.
You do need to be able to reproduce a test failure, which can be done by printing the inputs or the random seed used in a way that makes it trivial to rerun it.
I think it goes without saying. PBT shouldn't be random-random (e.g. use a timestamp or cryptographic seed), it should be deterministically pseudorandom if it uses random values. You shouldn't be able to run it 10 times and get 9 pass and one failure. It's either 10 passes or 10 failures.
The most memorable discussion I had around PBT was with a colleague (a skip report) who saw "true" randomness as a net benefit and that reproducibility was not a critical characteristic of the test suite (I guess the reasoning was then it could catch things at a later date?). To be honest, it scared the hell out of me and I pushed back pretty hard on them and the broader team.
I have no issue with a psuedo-random set of test cases that are declaratively generated. That makes sense if that is what is meant by PBT. Since it is just a more efficient way of testing (and you would assume this would allow you to cast a wider net).
Re: Why Property Testing Finds Bugs Unit Testing Does Not (2021)
#30I would love to used PBT more, but many tests I write have only one answer per input. Think sum like aggregations. For then it's not clear how would one derive the answer from the generated inputs, that is what code is for. But PBT can be great for pruning out crashes you don't expect while parsing.
Not quite sure what you mean by "only one answer per input" (that it's a function, i.e. a 1:1 mapping?), but there are of lots of properties that aggregations might typically need to satisfy, e.g. off the top of my head:
# Identity element
forAll(pre, post) {
assertEqual(
agg(pre ++ [agg([])] ++ post),
agg(pre ++ post)
)
}
# Invariant to order
forAll(elems, seed) {
assertEqual(
agg(elems),
agg(permute(elems, seed))
)
}
# Left-associative
forAll(xs, ys, zs) {
assertEqual(
agg([agg(xs ++ ys)] ++ zs),
agg(xs ++ ys ++ zs)
)
}
# Right-associative
forAll(xs, ys, zs) {
assertEqual(
agg(xs ++ [agg(yz ++ zs)]),
agg(xs ++ ys ++ zs)
)
}
(FYI these typical properties of a (commutative) monoid, which is an algebraic structure that describes many "aggregation-like" operations)