Is there a Pytest equivalent to the unittest unittest.TestLoader.loadTestsFromModule() method?

Viewed 119

I am working on a program that modifies test suites.
In the original implementation, there was only support for the unittest framework. I am trying to add support for Pytest now.

With the default unitest module, I could keep the modified tests as ASTs in memory, which I convert to a module, and finally, I can create a test suite from that, and run it.

#create module
code = test.AST.compile()
module = types.ModuleType(test.name)
module.__dict__.update(scope)
exec(code, module.__dict__)
#create suite
suite = unittest.TestLoader().loadTestsFromModule(module)
#run test
suite.run()

From everything that I can find in the Pytest documentation, this seems not possible.
Pytest needs the testfiles to function.

Does someone know if this is either possible for Pytest or a possible workaround? I don't want to write hundredths of modified tests to the filesystem, as this would be more expensive than keeping them in memory.

1 Answers

Okay so thanks to lead developer nicoddemus I have found the answer, I've decided to share it also here.

The gist of it is as follows: From inside my program I still create the module in memory as above, and I push the module on the stack. Next, I call pytest with pytest.main:

# Create Module
code = test.AST.compile()
module = types.ModuleType(test.name)
module.__dict__.update(scope)
exec(code, module.__dict__)

modules.append(module)
# Run test
result = pytest.main([test.filename, "-p", "inject_module"])

In inject_module.py I have defined the following hook, which simply performs the default logic, but sets the _obj attribute of the Module to my module on the stack.

def pytest_pycollect_makemodule(path, parent) -> "Module":
    if path.basename == "__init__.py":
        pkg: Package = Package.from_parent(parent, fspath=path)
        return pkg
    mod: Module = Module.from_parent(parent, fspath=path)
    mod._obj = modules.pop()
    return mod
Related