nedbat / coveragepy

The code coverage tool for Python
https://coverage.readthedocs.io
Apache License 2.0
3.02k stars 433 forks source link

How to get a mapping dictionary from a function to corresponding test function and vice versa? #1856

Open thaiminhpv opened 1 month ago

thaiminhpv commented 1 month ago

I am wondering if this is even possible or not by using coveragepy (or pytest-cov).

I want to get a mapping dictionary dict[str, set[str]] from a function to corresponding test functions from the execution trace by running pytest on the source code.

The name of function and the name of test might be in pytest nodeid format (e.g. module_abc.xyz::ClassA::test_method)

Example of what I expect

def A():
    B()

def B():
    pass

def test_A():
    A()

mapping = get_function2test_mapping()
assert mapping == {'A': ['test_A'], 'B': ['test_A']}

What I have tried

I tried to look at how coverage.py use sys.settrace to record the trace, but it is quite complex. I see the documentation also say that the trace is dump to .coverage sqlite database. But I do a simple test I find nothing useful in the dumped db.

I also tried to implement a pytest plugin using sys.settrace, but the setup and teardown part have different fixture scope and quite complex, because I want to include setup and teardown functions also. I think the problem is also solved if we can get the setup and teardown function given the test case.

But as I currently understand (PLEASE CORRECT ME IF I AM WRONG) it seems like coverage.py only collect information is about "line coverage" (or arcs for "branch coverage"), and the information about each execution session got discarded, so the dumped database is not helpful.

Am I correct? How can I get a mapping from pytest nodeid to function nodeid, based on the coverage.py dumped trace output?

nedbat commented 1 month ago

Coverage.py doesn't directly provide the information you want, but it can help. Use the dynamic contexts feature to record lines separately for each test. Then you'll have to map the line numbers back to functions. The contexts_by_lineno should be helpful. Let us know what you come up with.