[Python-ideas] Simplicity of C (was why is design-by-contracts not widely)

Cameron Simpson cs at cskk.id.au
Sun Sep 30 00:44:22 EDT 2018


On 30Sep2018 12:17, Chris Angelico <rosuav at gmail.com> wrote:
>At the moment, I'm seeing decorator-based contracts as a clunky
>version of unit tests. We already have "inline unit testing" - it's
>called doctest - and I haven't seen anything pinned down as "hey, this
>is what it'd take to make contracts more viable". Certainly nothing
>that couldn't be done as a third-party package. But I'm still open to
>being swayed on that point.

Decorator based contracts are very little like clunky unit tests to me. I'm 
basing my opinion on the icontracts pip package, which I'm going to start 
using.

In case you've been looking at something different, it provides a small number 
of decorators including @pre(test-function) and @post(test-function) and the 
class invariant decorator @inv, with good error messages for violations.

They are _functionally_ like putting assertions in your code at the start and 
end of your functions, but have some advantages:

- they're exposed, not buried inside the function, where they're easy to see 
  and can be considered as contracts

- they run on _every_ function call, not just during your testing, and get 
  turned off just like assertions do: when you run Python with the -O 
  (optimise) option. (There's some more tuning available too.)

- the assertions make qualitative statements about the object/parameter state 
  in the form "the state is consistent if these things apply";
  tests tend to say "here's a situation, do these things and examine these 
  results". You need to invent the situations and the results, rather than 
  making general statements about the purpose and functional semantics of the 
  class.

They're different to both unit tests _and_ doctests because they get exercised 
during normal code execution. Both unit tests and doctests run _only_ during 
your test phase, with only whatever test scenarios you have devised.

The difficulty with unit tests and doctests (both of which I use) and also 
integration tests is making something small enough to run but big/wide enough 
to cover all the relevant cases. They _do not_ run against all your real world 
data. It can be quite hard to apply them to your real world data.

Also, all the @pre/@post/@inv stuff will run _during_ your unit tests and 
doctests as well, so they get included in your test regime for free.

I've got a few classes which have a selftest method whose purpose is to confirm 
correctness of the instance state, and I call that from a few methods at start 
and end, particularly those for which unit tests have been hard to write or I 
know are inadequately covered (and probably never will be because devising a 
sufficient test case is impractical, especially for hard to envisage corner 
cases).

The icontracts module will be very helpful to me here: I can pull out the 
self-test function as the class invariant, and make a bunch of @pre/@post 
assertions corresponding the the method semantic definition.

The flip side of this is that there's no case for language changes in what I 
say above: the decorators look pretty good to my eye.

Cheers,
Cameron Simpson <cs at cskk.id.au>


More information about the Python-ideas mailing list