automat icon indicating copy to clipboard operation
automat copied to clipboard

Test helper that asserts all transitions occurred

Open markrwilliams opened this issue 7 years ago • 2 comments

Automat should have a test helper that asserts all transitions occurred.

It might go a little something like this:

tracer = TraceAllTransitions()
someMachineInstance.traceWith(tracer)

# testing intensifies

assertHasAllTransitions(tracer, for_=SomeMachine)

...where the tracer stuff would come from #36

markrwilliams avatar Jan 18 '17 06:01 markrwilliams

(Per @tomprince)

markrwilliams avatar Jan 18 '17 06:01 markrwilliams

At dinner tonight, @markrwilliams and I came up with some ideas:

  • a context manager which takes one or more Transitioner instances, and returns an object with accumulates transitions that occur while the context is active (as a set)
  • a test function that takes a MethodicalMachine instance and returns a set of all transitions that are defined

Then standard set-intersection tests can be used to decide if the right transitions have been exercised. You could merge the traces of multiple context managers to look at combined coverage, or you could use setUp/tearDown to merge multiple test cases and check the results at the very end of the test class.

class Foo(object):
    m = MethodicalMachine()
    ...
f = Foo()
with gather_transitions(f.m) as edges:
    f.trigger_stuff()
assert edges.all_transitions() == Foo.m.all_transitions()

(the difference between a machine instance, like Foo.m, and a transitioner instance, like f.m, is pretty important, both for implementation and for discoverability/learnability/error-reporting. my example probably gets at least one of them wrong)

This also avoids the need to be able to name specific transitions, since the sets contain opaque objects (one per transition). This would let us continue to keep the tracing function private, and these opaque objects would be the strings or tuples that the tracing function provides.

#37 would, of course, need a way to name these things.

Other questions:

  • should the gatherer context-manager look at all transitions, of all Automat state machines? Or should we give it a list of classes, and it looks for all transitions of all machines used by those classes? Or a list of state machines? Or a list of transitioners?
  • pointing at specific transitioners would require that those objects exist before the context is entered, but many apps will only create the object that uses the state machine inside some wrapper method, so marking the class/factory object seems more usable (just like mock.patch can patch something other than what's about to be called)
  • using a context manager makes it easy to invoke multiple methods, in case it takes multiple steps to set up the transition
  • this would work by using the private tracing function from #56 to accumulate transitions. we might want to enhance that method to accomodate multiple tracers (added/removed with a set, rather than a push-pull stack or return-the-old-tracer one-at-a-time method). This would allow the set_trace method to be used in the tests, while debugging the code that is failing to hit all transitions.

warner avatar May 21 '17 07:05 warner