We’ve been discussing internally for quite some time now that the fact that scenarios use doctests is a pain for at least a couple of reasons:
Hard to read and write due to lack of proper syntax highlighting in most editors, unnecessary verbosity with all the >>> prefixes, cannot use pyflakes…
The fact that the checks use strings only: which is often a annoying with Decimal values as Decimal("1.0") is different from Decimal("1.00")
That’s why we were thinking on a simple replacement of converting rst files to py, converting text to python comments, which could probably be automated with a script.
The checks could be changed to use an assertEqual()-like function previously converting the values to str in the automated script. Over time, str() conversions may be removed.
Sure, but I’m curious on understanding at least one or two examples where that is possible.
In Tryton most code will never generate any output and if it does (for example, you leave a print statement in the code) it will make the test fail, but it will not be a symptom of a problem in the code.
So I can only think of the tests we already have such as:
>>> from interlude import interact; interact(locals())
It throws the developer into an interactive Python console session for debugging/testing. The environment includes everything (variables, methods, imports, …) which is available in the doctest at this line. It works like the trytond-console, but on each test run it is set up freshly with a defined environment from the doc test including an always clean test database.
In the console session you can just do things like:
After finishing the console session, hit CTRL-D and the test-run continues.
Just copy paste 1:1 the fixes or findings from the console session back to the scenario test. Death simple and no reformatting or line-wise copy paste needed.
Iiuc one would use interlude for interfactive testing during development, and continue to use doctest for non-interactive testing (e.g. CI/CD pipeline). Do I understand correctly?
Nowadays everything is in Pythons stdlib included. Just putting
>>> breakpoint()
in your doctest, will start Pdb (Python Debugger). Enter command interact and you also get an interactive Python console session. Exit the console session with Ctrl-d and then quit (q) the debugger or continue (c) the test run.
We’ve already taken a similar approach @ coopengo.
Internally we write python files with a few annotations that are then converted to rst files. We ditched the “input / output” approach for tests in favor of homemade assert_XXX utils.
Debugging is easier, we can just manually edit the rst file with a single import trytond.modules.<my_module>.tests.scenario_...., and the python code will be executed as is (so breakpoints / prints / etc… will work as expected).
We always use Tryton’s infrastructure since we did not want to diverge too much. So we have a wrapper to run the tests that starts by converting the scenario*.py files to scenario*.rst, which are then processed as usual.
At first the converter interpreted special comments to identify expected returns:
invoice.state
# #Res# #'draft'
was turned into:
>>> invoice.state
'draft'
but we started a transition to assert_XXX tooling a few years back since it provides better information in case of failures. For instance, assert_in prints the contents of the list / the value we are checking in case of a fail, where:
>>> state in ['posted', 'paid']
True
will only tell us that got False, expected True.
We still use the conversion tool so far, but once (if…) all tests are converted to pure python (i.e. only uses assert_XXX), we may end up dropping rst files.
E.g. on sale and purchase it can be irritating to get different results when having [queue] worker activated or not in the trytond.conf. Especially if there is actually no worker running. So e.g. the expected sale state can be confirmed or processing.
The two last one maybe solved by adding to globs a method similar to assertEqual which would raise an error showing the difference. The problem is that it would make the scenario no more executable outside the infrastructure of Tryton.