This project is a tool for visualizing the coupling between classes dynamically in a Python project that uses pytest as the testing framework. It uses a combination of call stack tracing and graph visualization to help developers understand the relationships between classes and how they are used in the project. The graph visualization runs locally and launches in a browser. The graph consists of nodes representing classes and directed edges representing a dependency between them. This tool also supports filtering the graph to look at specific classes and identifying transitive dependencies.
In order to use this project:
- The test suite must be a working pytest suite (with unique test file names)
- The program must define/use classes
- Some additional python modules may need to be installed in your python environment such as
networkx,niceguiorplotly
In order to attach the coupling visulizer to a test suite, pytest fixtures will be used. An example of how to do this can be seen in the test.py file under test_project_1 where the following code has been added:
import sys
sys.path.append('../../../Group7Project2/src') # Change this to the path of the src directory
from tracer import my_tracer
@pytest.fixture(scope='session', autouse=True)
def my_fixture():
sys.settrace(my_tracer)
Note that the path to the src directory of this coupling visulizer may need to be updated for differing file locations.
This code can be added to individual pytest files to be used in the coupling visulizer. Additionally, this code could also be inserted into a new file named conftest.py if there are multiple test files within a test suite directory that will be used with the coupling visualizer.
To run the coupling visulizer, the run.py script within the src directory can be used which will invoke a tracer to run through the test suite, create a output log, and launch the GUI.
There are multiple ways to call run.py from within a terminal. The following examples assume that the current working direcotry is the src directory of this project.
With default paths (to the test program in this repository):
python run.py
With custom paths:
python run.py --test-path "../custom_test.py" --log-path "custom_log.csv"
With just one custom path:
python run.py --test-path "../test/custom_test.py"
There were some ideas that we did not have time to fully explore, but think would add to the project:
- Filtering based off the individual test runs through a tab-based ui
- Having the count of calls between classes represented as a number beside edges on the graph
- Showing transitive dependencies more explicitly through dotted lines between nodes
User study 1: we had generally positive feedback at this stage, and were able to implement their suggestions for colour coding dependencies and ease of startup. The ease of startup item in particular seemed quite important for our intended audience, so we made sure that it was a simple process to setup this program and make it work with an existing test suite.
User study 2: Also quite positive - users had a very easy time looking at the graph and figuring out what they were seeing. At this time, we hadn’t differentiated the appearance of transitive dependencies from direct dependencies on the graph - as we expected, our users had concerns about that because it was difficult to understand transitive dependencies in the first place. So we prioritized that functionality - making transitive dependencies red - in the final days before the deadline.