schrodinger.test.hypothesis.stateful module¶
- class schrodinger.test.hypothesis.stateful.RuleBasedStateMachineMetaClass(name, bases, dct)[source]¶
Bases:
hypothesis.stateful.StateMachineMeta
A metaclass that makes it easy to create simple rules for a RuleBasedStateMachine.
- ‘Simple’ in this context means that the rule we want to create
calls a method that takes no argument, and then
doesn’t check any results
The only thing that we’re testing with a rule like this is that calling the method never results in an unhandled exception. Ideally, we would check the results of calling methods, but even the lazy route is surprisingly useful in a state machine test. Advice: begin by adding as many of these simple rules as possible and then gradually replace them with richer rules and checks as the tests develop and experience indicates which checks are most valuable.
Suppose that we are testing self.panel in our state machine and want to call the methods ‘foo’ on self.panel.bar and ‘gar’ on self.panel.mar. We could write this:
class PanelMachine(stateful.RuleBaseStateMachine): def __init__(self): super(PanelMachine, self).__init__() self.panel = MyPanel() @stateful.rule() def foo(self): self.panel.bar.foo() @stateful.rule() def gar(self): self.panel.mar.gar()
But this quickly becomes tedious if we want to test a large number of such methods. Our metaclass will allow us to generate the desired rules for our state machine by adding strings to the SIMPLE_RULES tuple defined on the class:
@six.add_metaclass(RuleBasedStateMachineMetaClass) class PanelMachine(stateful.RuleBaseStateMachine): SIMPLE_RULES = ('panel.bar.foo', 'panel.bar.gar') def __init__(self): super(PanelMachine, self).__init__() self.panel = MyPanel()
- __init__(*args, **kwargs)¶
- mro()¶
Return a type’s method resolution order.
- class schrodinger.test.hypothesis.stateful.QtErrorCatchingRuleBasedStateMachine(trap_errors=True)[source]¶
Bases:
hypothesis.stateful.RuleBasedStateMachine
A RuleBasedStateMachine that fails if any Qt warnings or errors are reported or if any exceptions are raised in a slot. Without this class:
Qt warnings and errors are ignored.
Exceptions that are raised in a slot cause the test to fail with a “Exceptions caught outside of main thread:” message, but Hypothesis doesn’t report the steps required to reproduce the exception.
- Note
The error checkers in this class are implemented in two parts.
_recordException
and_recordQtWarningsAndErrors
record any problems that happen during a step, and the invariantcheckErrors
makes sure that no problems were recorded at the end of each step. Any exception raised in one of the_record
wouldn’t be recognized by Hypothesis and would instead go directly to the top-level error handler, so the two step approach is required.- Variables
FAIL_ON_QT_MSGS (tuple or list or set) – What Qt message types should trigger a test failure. By default warnings, criticals, and fatals lead to a test failure while debug and info messages are ignored. This can be modified in subclasses if desired.
QT_MSG_NAMES (dict(int, str)) – A mapping from QtMsgType values to a textual description.
IGNORE_WARN_PREFIXES (iterable(str)) – Any Qt warning message that starts with a string listed here will be ignored. Warning messages filtered by qt_message_handler.filter_qt_msg will be ignored regardless of this var.
- FAIL_ON_QT_MSGS = (1, 2, 3)¶
- QT_MSG_NAMES = {0: 'debug', 1: 'warning', 2: 'critical', 3: 'fatal', 4: 'info'}¶
- IGNORE_WARN_PREFIXES = ()¶
- __init__(trap_errors=True)[source]¶
- Parameters
trap_errors (bool) – Whether to override the top-level exception handler and catch all Qt warnings and errors. Setting this to False is only useful for interactive use of this object, i.e. instantiating one in a REPL. Otherwise, all REPL tracebacks would be swallowed by the excepthook.
- teardown()[source]¶
Reset the top-level exception handler and Qt’s message handler once the test is done.
- checkErrors()[source]¶
Fail if the current trial raised an unhandled exception or triggered a Qt warning or error.
- TestCase¶
alias of
hypothesis.stateful.QtErrorCatchingRuleBasedStateMachine.TestCase
- bundle(name)¶
- check_invariants()¶
- classmethod initialize_rules()¶
- classmethod invariants()¶
- classmethod rules()¶
- class schrodinger.test.hypothesis.stateful.PanelRuleBasedStateMachine(*args, **kwargs)[source]¶
Bases:
schrodinger.test.hypothesis.stateful.QtErrorCatchingRuleBasedStateMachine
A RuleBasedStateMachine for use with a Qt-based panel. Subclasses must define PANEL_CLASS, and the panel instance will be available as
self.panel
. Without this class:QTimers may not fire when they are supposed to
Errors that occur during painting will not be caught
Errors in stateful decorator arguments may cause pytest to segfault
- Variables
PANEL_CLASS (QtWidgets.QWidget) – The class of the panel to test.
- PANEL_CLASS = None¶
- __init__(*args, **kwargs)[source]¶
- Parameters
trap_errors (bool) – Whether to override the top-level exception handler and catch all Qt warnings and errors. Setting this to False is only useful for interactive use of this object, i.e. instantiating one in a REPL. Otherwise, all REPL tracebacks would be swallowed by the excepthook.
- teardown()[source]¶
Reset the top-level exception handler and Qt’s message handler once the test is done.
- check_invariants()[source]¶
Make sure we process events after each step so that any QTimers with timeouts of 0 will fire when they’re supposed to.
- FAIL_ON_QT_MSGS = (1, 2, 3)¶
- IGNORE_WARN_PREFIXES = ()¶
- QT_MSG_NAMES = {0: 'debug', 1: 'warning', 2: 'critical', 3: 'fatal', 4: 'info'}¶
- TestCase¶
alias of
hypothesis.stateful.PanelRuleBasedStateMachine.TestCase
- bundle(name)¶
- checkErrors()¶
Fail if the current trial raised an unhandled exception or triggered a Qt warning or error.
- classmethod initialize_rules()¶
- classmethod invariants()¶
- classmethod rules()¶
- bundles: Dict[str, list]¶
- names_to_values: Dict[str, Any]¶