javagradletestngjacococlover

Gradle + TestNG: How to list which classes were touched by a unit test?


I'd like to list what classes are touched during the execution of each unit test. I want to discover which tests have an overly large scope and should use a smaller unit instead. Measuring the code coverage via IntelliJ or JaCoCo doesn't help me as I cannot drill down to a single test. Has anyone managed to do something similar? I found a similar question which was asked ten years ago, but never answered. I currently use Java 8 with Gradle and TestNG. I feel like I have to build some Gradle plugin or modify TestNG in some way, but I have no idea where to start.

Any help is greatly appreciated.


Solution

  • OK, I've discovered that Openclover can do this. I've setup a dummy maven project and when I execute the tests via this command chain:

    mvn clean clover:setup test clover:aggregate clover:clover
    

    Then clover generates a report in the "target\site\clover" subdirectory of my project. In that directory is an index.html which you can use to browse through the results. You need to navigate to a test and to a certain test method to see the breakdown. It looks like this:

    enter image description here

    We can see that the method testCalculateBalance of BalanceCalculatorTest covers BalanceCalculator, PriorServiceBalanceProvider and TimeAccount, but we don't see TimeAccountProvider, because it is mocked in the test. I'll paste the code snippets, so you get the full picture. Bottom line is, it works, but it is not very user friendly.

    public class BalanceCalculatorTest {
    
    @Test
    public void testCalculateBalance() {
        TimeAccountProvider timeAccountProvider = Mockito.mock(TimeAccountProvider.class);
        Mockito.doReturn(Collections.singleton(new TimeAccount())).when(timeAccountProvider).getTimeAccounts();
        BalanceCalculator balanceCalculator = new BalanceCalculator(timeAccountProvider);
        Assert.assertEquals(balanceCalculator.calculateBalance(), 2);
    }
    

    }

    public class BalanceCalculator {
    
    private final TimeAccountProvider timeAccountProvider;
    
    public BalanceCalculator(TimeAccountProvider timeAccountProvider) {
        this.timeAccountProvider = timeAccountProvider;
    }
    
    public int calculateBalance() {
        Set<TimeAccount> timeAccounts = timeAccountProvider.getTimeAccounts();
        int sum = 0;
        for (TimeAccount timeAccount : timeAccounts) {
            Set<TimeAccountDetail> bookings = timeAccount.getTimeAccountDetails();
            sum += bookings.stream()
                    .mapToInt(TimeAccountDetail::getAmount)
                    .sum();
        }
        sum += new PriorServiceBalanceProvider().getPriorBalance();
        return sum;
    }
    

    }