How To Stop Worrying And Start Writing Tests Based On Properties

In some articles, invariants are singled out separately on such topics, but in my opinion, the border is too fragile here, since most of these invariants are direct consequences of the requirements, so perhaps I’ll dump everything.A small list of examples from a variety of areas that are convenient for checking properties:A class field must have a previously assigned value (setters),The repository should be able to read the previously recorded item,The adding a previously non-existing item to the repository does not affect previously added items,Many dictionaries can not store several different items with the same key,The base64 encoding result must contain only characters from the base64 alphabet,The route building algorithm must return a sequence of allowable movements that will lead from point A to point B,For all points of the contour constructed should be performed f(x, y) = const,The signature verification algorithm should return True if the signature is real and False otherwise,As a result of orthonormalization, all vectors in the basis must have unit length and zero reciprocal scalar products,The vector transfer and rotation operations should not change its lengthIn principle, one could say that everything is finished, use test oracles, or look for properties in the requirements, but there are several interesting “special cases” that I would like to mention separately.Stateful testing and state testingSometimes you need to test something that has a state.In this case, the easiest way:Write a test that checks the correctness of the initial state (for example, that the container just created is empty),Write a generator that, using a set of random operations, will bring the system into some arbitrary state,Write tests for all operations using the result of the generator as the initial state.Very similar to mathematical induction:To prove claim one,To prove the assertion N + 1, assuming that the assertion N is true.Another method (sometimes giving a little more information about where it broke) is to generate a valid sequence of events, apply it to the system under test and check the properties after each step.Back and forthIf suddenly there is a need to test a couple of functions for the direct and inverse transformation of some data, then consider yourself lucky:input = arbitrary_data()assert decode(encode(input)) == inputGreat for testing:Serialization-deserializationEncrypt-decryptEncoding decodeTransformations of the basic matrix into quaternion and backThe direct and inverse coordinate transformationA direct and inverse Fourier transformA private, but the interesting case is the inversion:input = arbitrary_data()assert invert(invert(input)) == inputA striking example is the inversion or transposition of a matrix.IdempotencySome operations do not change the result when reapplied..Typical examples:Sorting,All sorts of vectors and bases,Re-add an existing item to the set or dictionary,Re-write the same data in some property of the object,Casting data to canonical form (spaces in JSON lead to a single style for example).You can also use idempotency to test serialization-deserialization if the usual decode (encode (input)) == input method is not suitable because of the different possible representations for equivalent input data (again, there are extra spaces in some JSON):def normalize(input): return decode(encode(input))input = arbitrary_data()assert normalize(normalize(input)) == normalize(input)Different paths, one resultHere the idea boils down to exploiting the fact that sometimes there are several ways to do the same thing..It may seem that this is a special case of a test oracle, but in fact, it is not quite so..The simplest example is the use of commutativity of some operations:a = arbitrary_value()b = arbitrary_value()assert a + b == b + aIt may seem trivial, but it’s a great way to test:Addition and multiplication of numbers in a nonstandard representation (bigint, rational, that’s all),“Adding” points on elliptic curves in finite fields (hello, cryptography!),A union of sets (which can have completely non-trivial data structures inside)In addition, adding the elements to the dictionary has the same property:A = dict()A[key_a] = value_aA[key_b] = value_bB = dict()B[key_b] = value_bB[key_a] = value_aassert A == BThe variant is more complicated — I thought for a long time how to describe in words, but only a mathematical notation comes to mind..In general, such f (x) transformations are often found, for which the property f (x + y) = f (x) ⋅ f (y) holds, and both the argument and the result of the function are not necessarily a number, but + and ⋅ are just some binary operations on these objects..What can this test:Addition and multiplication of any strange numbers, vectors, matrices, quaternions (a cdot (x+y) = a cdot x + a cdot y)Linear operators, in particular, all integrals, differentials, convolutions, digital filters, Fourier transforms, etc ()Operations on the same objects in different representations,For example:M(q_a cdot q_b) = M(q_a) cdot M(q_b)these are unit quaternions, and M (q) is the operation of converting a quaternion into an equivalent basis matrix,F[a circ b] = F[a] cdot F[b]these are signals, — convolution, — multiplication, and — Fourier transform.An example of a slightly more “routine” task is to test some tricky dictionary merge algorithm in some way:a = arbitrary_list_of_kv_pairs()b = arbitrary_list_of_kv_pairs()result = as_dict(a)result.merge(as_dict(b))assert result == as_dict(a + b)SummaryThat’s basically all that I wanted to tell in this article..I hope it was interesting, and a little more people will begin to put all this into practice..To make the task a little easier, I will give a list of frameworks of different degrees of fitness for different languages:Python: HypothesisRust: ProptestScala: ScalacheckC++: RapidcheckJavaScript: FactCheckGo: GopterAnd, of course, a special thanks to people who once wrote wonderful articles, thanks to which I learned about this approach a couple of years ago, stopped worrying and started writing tests based on properties:alexwlchan.net/talks/hypothesis-introfsharpforfunandprofit.com/posts/property-based-testing-2. More details

Leave a Reply