Expand my Community achievements bar.

SOLVED

How to mock a util class with static methods in Junit5 using wcm io?

Avatar

Employee

Hi,

I am writing my first junit test for a workflow process and I am trying to write it using the AEM context (WCM io)
and my workflow process also has a util class method used in it. Here I am facing two problems one with
providing the context (which contains the resource resolver factory and the other objects) to the workflow process execute method in the test method and
the mocking of utils class in Test class.

 

Note: We can mock the util class if we use powermockito, but powermockito works only with Junit4, but I have to write my test case in Junit5.

 

below is an excerpt of my code:

@ExtendWith(AemContextExtension.class)
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class WorkflowProcessTest {

AemContext context = new AemContext(ResourceResolverType.RESOURCERESOLVER_MOCK);
@Mock
WorkItem workItem;
@Mock
WorkflowData workflowData;
@Mock
WorkflowSession workflowSession;
@Mock
MetaDataMap metaDataMap;
@Mock
private QueryBuilder queryBuilder;
@Mock
private Query qbQuery;
@Mock
ResourceResolverFactory resourceResolverFactory;

@Mock
private SearchResult qbResult;
@Mock
Session adminSession;
@Mock
ResourceResolver resolver;

WorkflowProcess workflowProcess;

@BeforeEach
void setUp() throws LoginException {
resourceResolverFactory = context.registerService(ResourceResolverFactory.class, new MockResourceResolverFactory());
context.registerAdapter(ResourceResolver.class, Session.class, mock(Session.class));
mockPayload();
resolver = context.resourceResolver();
when(resourceResolverFactory.getServiceResourceResolver(any())).thenReturn(resolver);

}

@test
void testExecute() throws RepositoryException,WorkflowException {

//Some more code here
workflowProcess = new WorkflowProcess();
workflowProcess.execute(workItem, workflowSession, metaDataMap);
//workflowProcess = context.registerInjectActivateService(new workflowProcess());
verifyMetadata(metadataNode);

}

private void verifyMetadata(Node metadataNode) throws RepositoryException {
//assert statement here

}

void mockPayload() {
//payload mock here

}
}

 

Can someone help on those two?

 

Your help is much appreciated.

 

Thanks in advance,
Adilakshmi

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

I've actually written a blog for this for JUNIT5, with code examples and dependencies:

 

PowerMock is a Java framework that allows you to unit test code that uses static methods, constructors, and private methods. PowerMock uses a combination of bytecode manipulation and reflection to enable the mocking of these types of methods.

PowerMock is not officially supported by JUnit 5. PowerMock is built on top of EasyMock and provides additional functionality such as the ability to mock static methods, constructors, and private methods. PowerMock uses a different test runner than the one provided by JUnit 5, so it is not directly compatible with JUnit 5.

Alternatively, you can use mockito-inline for inline mocking, it allows you to mock static methods, final classes, and methods, and more.

JUnit 5 provides its own extension model that allows for the creation of custom test runners and the registration of extensions. You could write your own test runner for PowerMock that works with JUnit 5 or use a different mocking framework that is compatible with JUnit 5.


Utils Class:

public class Utils {
    public static String getString() {
        return "Original string";
    }
}


Test Class:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.mockito.Mockito;

public class MyTest {

    @test
    public void testStaticMethod() {
        // mock the static method of the Utils class
        Mockito.mockStatic(Utils.class);
        Mockito.when(Utils.getString()).thenReturn("Mocked string");
       
        // create an instance of the class that calls the static method
        MyClass myClass = new MyClass();
        assertEquals("Mocked string", myClass.getStringFromUtils());
    }
}

 

Read more:Mocking Static Methods in JUNIT5 - Sourced Code

View solution in original post

4 Replies

Avatar

Community Advisor

Hi @adimangalampalli 

WCM io library is a utility to mock AEM resources during test time. If you have created a new static method then please avoid using creating a static method as this won't be considered as best practice in java and for the same reason mockito framework doesn't provide the capability to mock static methods by default. You can create services and methods to achieve the same.
However for mocking the static method, please refer below points:

Regards,

Arpit Varshney

 

Avatar

Correct answer by
Community Advisor

I've actually written a blog for this for JUNIT5, with code examples and dependencies:

 

PowerMock is a Java framework that allows you to unit test code that uses static methods, constructors, and private methods. PowerMock uses a combination of bytecode manipulation and reflection to enable the mocking of these types of methods.

PowerMock is not officially supported by JUnit 5. PowerMock is built on top of EasyMock and provides additional functionality such as the ability to mock static methods, constructors, and private methods. PowerMock uses a different test runner than the one provided by JUnit 5, so it is not directly compatible with JUnit 5.

Alternatively, you can use mockito-inline for inline mocking, it allows you to mock static methods, final classes, and methods, and more.

JUnit 5 provides its own extension model that allows for the creation of custom test runners and the registration of extensions. You could write your own test runner for PowerMock that works with JUnit 5 or use a different mocking framework that is compatible with JUnit 5.


Utils Class:

public class Utils {
    public static String getString() {
        return "Original string";
    }
}


Test Class:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.mockito.Mockito;

public class MyTest {

    @test
    public void testStaticMethod() {
        // mock the static method of the Utils class
        Mockito.mockStatic(Utils.class);
        Mockito.when(Utils.getString()).thenReturn("Mocked string");
       
        // create an instance of the class that calls the static method
        MyClass myClass = new MyClass();
        assertEquals("Mocked string", myClass.getStringFromUtils());
    }
}

 

Read more:Mocking Static Methods in JUNIT5 - Sourced Code

Avatar

Employee

Thanks @BrianKasingli for your answer, I used the Mockito.mockStatic to mock my util class and it worked.

 

Thanks,

Adilakshmi

Avatar

Level 1

Hi @BrianKasingli , I am having the same problem, that  I want to mock a static class in Junit 5 test, which is written using WCM IO extension and AemContext in it. I am able to write the junit without using WCM IO and AemContext, but is it possible to mock the Util class with static methods in my test class in this case.

 

My Impl class:

@Model(adaptables = {
        SlingHttpServletRequest.class }, adapters = MyModel.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL, resourceType = MyModelImpl.RESOURCE_TYPE)
public class MyModelImpl implements MyModel {

    protected static final String RESOURCE_TYPE = "some resource type";

    @ValueMapValue
    private String link;

    //other props

    @PostConstruct
    public void init() {
        link = MyUtils.getCorrectUrlForGivenUrlProperty(link);
		// other logic
    }

    @Override
    public String getLink() {
        return Link;
    }

}

MyModelTest class:

@ExtendWith({ AemContextExtension.class, MockitoExtension.class})
class MyModelImplTest {

    private final AemContext aemContext = new AemContext();

    private MyModel myModel;


    @BeforeEach
    void setUp() {
        //Mockito.mockStatic(MyUtils.class);
        //when(MyUtils.getCorrectUrlForGivenUrlProperty("/content/page")).thenReturn("/content/page.html");
        aemContext.addModelsForClasses(MyModelImpl.class);
        aemContext.load().json("/com/aem/bd/core/models/impl/MyModelImplTest.json", "/content");
    }

    @Test
    void testPropsOfMyModel() {
        aemContext.currentResource("/content/myModel");
        myModel = aemContext.request().adaptTo(MyModel.class);
        assertEquals("/content/page.html", myModel.getLink());
    }
}

In the above test class myModel is always coming null in testPropsOfMyModel() method because the aemContext could not initialize MyModel properly because of MyUtils class.

 

Could you please help me on this?

 

Thanks in advance.

Suman