Search code examples
javajunit5

How to print CustomDisplayNameGenerator value in the console using Junit 5 and java?


I want to print CustomDisplayNameGenerator value in the console using junit 5 and java.

import org.junit.jupiter.api.DisplayNameGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;

public class CustomDisplayNameGenerator extends DisplayNameGenerator.Standard {
    private static final Logger logger = LoggerFactory.getLogger(CustomDisplayNameGenerator.class);

    @Override
    public String generateDisplayNameForClass(Class<?> testClass) {
        return replaceCamelCase(super.generateDisplayNameForClass(testClass));
    }

    @Override
    public String generateDisplayNameForNestedClass(Class<?> nestedClass) {
        return replaceCamelCase(super.generateDisplayNameForNestedClass(nestedClass));
    }

    @Override
    public String generateDisplayNameForMethod(Class<?> testClass, Method testMethod) {

        StringBuilder result = new StringBuilder();
        result.append( "Test" + ";");
        result.append( "Project" + "Test;");
        result.append( "JIRA id" + "435345;");
        return result.toString();

    }

    String replaceCamelCase(String camelCase) {
        StringBuilder result = new StringBuilder();
        result.append(camelCase.charAt(0));
        for (int i = 1; i < camelCase.length(); i++) {
            if (Character.isUpperCase(camelCase.charAt(i))) {
                result.append(' ');
                result.append(Character.toLowerCase(camelCase.charAt(i)));
            } else {
                result.append(camelCase.charAt(i));
            }
        }
        return result.toString();
    }
}

I am not sure what it is I need to do further. Can someone help me please? Here is the code so far I have got:

import Framework.Annotations.Common.*;
import org.junit.jupiter.api.*;
import java.lang.annotation.Annotation;
import static org.junit.jupiter.api.DisplayNameGenerator.getDisplayNameGenerator;

@DisplayNameGeneration(CustomDisplayNameGenerator.class)
public class JUnit5GeneratedExample  {

    @Test
    void simpleTestExecution() {
        Annotation displayNameGeneration = getClass().getAnnotation(DisplayNameGeneration.class);
        if (displayNameGeneration != null) {
            System.out.println(displayNameGeneration.toString());
            DisplayNameGenerator name = getDisplayNameGenerator(DisplayNameGenerator.Standard.class);
            System.out.println(name.generateDisplayNameForMethod(CustomDisplayNameGenerator.class,  new Object(){}.getClass().getEnclosingMethod()));
        }
        System.out.printf("This is printed");
    }
}

I am trying to print below highlighted text in my console. Is there a way to print CustomDisplayNameGenerator in the console?

enter image description here


Solution

  • The code looks ok, there is only one small issue is here:

    DisplayNameGenerator name = getDisplayNameGenerator(DisplayNameGenerator.Standard.class);
    

    This line will return an instance of DisplayNameGenerator.Standard, so - in your case - you'll want to use your own class there:

    DisplayNameGenerator nameGenerator = DisplayNameGenerator.getDisplayNameGenerator(CustomDisplayNameGenerator.class);
    System.out.println(nameGenerator.generateDisplayNameForMethod(CustomDisplayNameGenerator.class,  new Object(){}.getClass().getEnclosingMethod()));
    

    On the other hand, this won't be much different from directly calling the constructor:

    DisplayNameGenerator nameGenerator = new CustomDisplayNameGenerator();
    System.out.println(nameGenerator.generateDisplayNameForMethod(CustomDisplayNameGenerator.class,  new Object(){}.getClass().getEnclosingMethod()));
    

    As discussed in the comments, I found a better solution for this: you can define a custom test extension that implements the BeforeTestExecutionCallback :

    public class PrintTestNameBeforeEach implements BeforeTestExecutionCallback {
        @Override
        public void beforeTestExecution(ExtensionContext context) {
            System.out.println(context.getDisplayName());
        }
    }
    

    Now, you can simply annotate any test class with @ExtendWith(PrintTestNameBeforeEach.class) and all the methods will be printed, using the custom display name generator if you have one.

    @ExtendWith(PrintTestNameBeforeEach.class)
    @DisplayNameGeneration(CustomDisplayNameGenerator.class)
    class JUnit5Callbacks {
    
        @Test
        void myFirstTest() {
            System.out.println("running the first test...");
        }
    
        @Test
        void mySecondTest() {
            System.out.println("running the second test...");
        }
    }
    

    Ps: I wrote a small medium article about it, you can see all the steps here: https://medium.com/javarevisited/junit5-callbacks-in-less-than-3-minutes-55a87e000fcc