Property-Based Testing in Rust with Arbitrary
greyblake.com
greyblake.com
Unfortunately, I'm already convinced and know how to write the tests — what I wish I could find is some resource that would hone my ability to identify worthwhile properties. The best one I know of and go back to time and time again is https://fsharpforfunandprofit.com/posts/property-based-testi..., but I really wish I could find more.
The author also published a tool for PBT:nif web front ends which sounds interesting.
https://pragprog.com/titles/fhproper/property-based-testing-...
Alternatively reach out to him in an email and see if he'll be willing to let you buy access. I personally found it a pretty good course where he had spent a reasonable amount of time coming up with both decent examples to highlight how it was going to work as well as create some nice rules of thumb as starting points to think about properties.
-[0]: https://ericnormand.podia.com/beginning-property-based-testi...
[0] https://en.m.wikipedia.org/wiki/Abstract_algebra [1] https://en.m.wikipedia.org/wiki/Binary_relation
E.g. if you had "max_speed_kph: Option<u64>", your tests might never check what happens if max_speed_kph is 0.
https://github.com/intel/yarpgen
https://github.com/intel/yarpgen/blob/main/papers/yarpgen-oo...
(see "Policies for constants", page 196:8.)
I’ve had some success with property based testing, at least for heavily algorithmic code. For example I wrote a kNN implementation after finding all sorts of edge cases in others (floating point shenanigans included). You can succinctly capture properties like: returning the right number of clusters, each point being closest to its cluster’s mean, each cluster being centred on its centroid, all points being assigned to a cluster, and all clusters being non-empty. But even then you could game things if you wanted to.
Where I’ve struggled is in the general case. Most tests don’t have good property based alternatives, beyond just repeating the logic of the code under test, which seems pointless. And so you have this constant tension of wondering if a particular test could or should be property based.
And that (Quickcheck at least) has a bunch of primitive generators that you build your structures out of.
No idea, if it's doable in Rust. I just find it strange that it works on a stream of random bytes out of which you magically get some structures.
I remember more circa 2010 attending a presentation by the guys from QuviQ who mentioned that their solution was used by the automotive industry in Sweden to verify embedded systems.
The difficult bit is finding invariants or approximations, but doing so is half of what makes the code more robust anyway!
The operational problem is that the tests sometimes take a little longer to run, so sometimes they have to be in a low-prio suite.
Fuzzing can be thought of as property based testing.
The key to PBT is that it allows tests to be generated and minimized automatically, enabling enormously larger volumes of tests than if the tests have to be generated manually.
1. This example [1] compares a SIMD-accelerated implementation of an algorithm vs the naive implementation. This is usually referred to as an "oracle".
2. This example [2] tests an XML document object model library. The tests construct a sequence of operations to apply to a document ("add an element", "delete an element", "move an element" etc) and then assert properties that you expect to be true for a DOM tree (a parent and child are always cross-linked, for example)
[1]: https://github.com/shepmaster/jetscii/blob/8d7e44ad7da990ef1...
[2]: https://github.com/shepmaster/sxd/pull/21/files#diff-fc21cbf...
Our biggest use case has been testing our database materialization. We have a somewhat complicated hierarchical organization tree/forest within our database. In order to efficiently query those structures, we materialize the transitive closure of these relationships. TL;DR; we populate a row for each (org, ancestor) and maintain that via postgres triggers that fire whenever we mutate things.
The prop test that tests it all does three things. First, it establishes an arbitrary that captures all the possible shapes of organization trees. Second, we define the set of mutations (add a child, switch parents, delete a grandparent, etc.) that may occur. Third, we have code for reading/writing org trees to and from the DB.
The test then generates an org tree, syncs it to the db, performs 1 or more mutations on the tree and then compares what's in the database with the resulting tree.
Overall it's been pretty great. I highly recommend property tests, especially when modeling complex data in an external system.
Biggest difficulty for me was that some combinations of operations were illegal and I had to think about all the edge cases and filter them out, and this took a long time.
My SO works in hardware, and she says they always use a constraint solver to generate test cases / test vectors, and she never understood why this wasn't popular in software. I googled it a bit and found lots of academic papers but no concrete implementation.
I've also thought about generating test vectors using a generator based on Markov chains, I wrote about that here [0], based on this [1] submission.
I'm not familiar enough with either using constraint solvers to generate test cases, or Markov chains, to know if I'm talking nonsense here or is it just something that nobody thought to develop properly.
There’s also a TryFrom which returns a Result, in the event your conversions are fallible.
Just wondering, is there a reason for not having more specific names in rs projects?