ExploTest is a tool that turns exploratory test runs into unit tests by capturing and serializing run-time arguments.
By adding the @explore decorator to any function, ExploTest automatically generates unit tests with assertions based
on the previous execution values.
pip install ExploTestpython3 -m pip install -e <path/to/explotest>On any function or method (except for closures), add the @explore decorator. When this function (the
function-under-test or FUT) is called at runtime, a
unit test will be generated and saved in same directory as the file of the FUT.
The @explore decorator accepts two optional parameters, mode and explicit_record.
mode determines how the run-time arguments are reconstructed in the unit test:
- Setting this to
"p"or"pickle"results in ExploTest "pickling" (a Python specific binary serialization) each argument into a file, then loading this file in the unit test. ExploTest uses the dill library for pickling, which enables support for function arguments among others. However, objects that cannot be pickled ( e.g., Pandas DataFrames) cannot be saved. This is the default behaviour. - Setting this to
"a"results in ExploTest attempting to reconstruct the parameter by creating a new object and setting all its fields to the runtime argument. For example, when running the code
class Bar:
x = 1
@explore(mode="a")
def baz(b):
return
baz(Bar())the unit test
@pytest.fixture
def generate_b():
clone_b = scratchpad.Bar.__new__(scratchpad.Bar)
setattr(clone_b, 'x', 1)
return clone_b
def test_baz(generate_b):
b = generate_b
return_value = scratchpad.baz(b)
assert return_value is Noneis generated. This will not work for some objects, namely ones that are "more" than just a collection of fields or have
fields that cannot be setattr'd. In this case,
ExploTest will try to fall back on pickling.
explicit_record determines when ExploTest generates a unit test. By default, this is False and so ExploTest
generates a unit test everytime
a function with the @explore decorator is called. However, this may become unwieldy if the function is called many
times and
only certain tests are desired. By setting explicit_record to True in a function, a unit test will only be created
if the function body calls
explotest_record(). Note that due to implementation details, this is not thread safe.
For example,
@explore(explicit_record=True)
def fib(n):
if n <= 1:
explotest_record()
return 1
return fib(n - 1) + fib(n - 2)A unit test will only be generated for when n <= 1.
Create a venv, then install pip-tools. Run pip-compile as specified.
python3 -m venv .venv
pip install pip-tools
pip-compile -o requirements.txt ./pyproject.toml
pip install -r requirements.txtExploTest is free and open source software, licensed under the GNU LGPL v3 or any later version.