Home > Software engineering >  Mock static method called from constructor in java class
Mock static method called from constructor in java class

Time:06-16

I want to mock the static method being invoked from the constructor of my class.

My class:

package com.javaeasily.demos.junit;

import java.util.ArrayList;

public class MyClass {

private int number;
private static final ArrayList<String> ACTIVE_SERVICES_POST_RECONFIGURE = new ArrayList<>();

// Only allow construction if number is greater than one
MyClass() {
    ACTIVE_SERVICES_POST_RECONFIGURE.add("my-node-"   NodeUtils.getMyNode());
}

public void reconfigureNode() {
    if (ACTIVE_SERVICES_POST_RECONFIGURE.isEmpty()) {
        return;
    }
 }
}

Here NodeUtils.getMyNode() is the static method being invoked from the constructor of the class.

NodeUtils.java Class:

package com.javaeasily.demos.junit;

import org.apache.maven.surefire.shade.booter.org.apache.commons.lang3.StringUtils;
public class NodeUtils {
private static final String HOSTNAME_PREFIX = "my-node-";

public static String hostnameToNode(String hostname) {
    if (!hostname.startsWith(HOSTNAME_PREFIX)) {
        throw new IllegalArgumentException(hostname   " is not recognized hostname");
    }
    return StringUtils.removeStart(hostname, HOSTNAME_PREFIX);
}

public static String getHostname() {
    return System.getenv("HOSTNAME");
}

public static String getMyNode() {
    return hostnameToNode(getHostname());
  }
}

MyClassTest.java

package com.javaeasily.demos.junit;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class MyClassTest {
private MyClass myclass;

@BeforeEach
public void SetUp() {
    myclass = new MyClass();
}

@Test
public void testReconfigureNode() {
    myclass.reconfigureNode();
 }
}

When I try & run the only test case I get the following error:

java.lang.NullPointerException
at com.javaeasily.demos.junit.NodeUtils.hostnameToNode(NodeUtils.java:8)
at com.javaeasily.demos.junit.NodeUtils.getMyNode(NodeUtils.java:19)
at com.javaeasily.demos.junit.MyClass.<init>(MyClass.java:12)
at com.javaeasily.demos.junit.MyClassTest.SetUp(MyClassTest.java:11)

I am not sure how do we mock the method to avoid this error?

Since I am new to Java I am not able to catch this. Any help here is appreciated.

CodePudding user response:

So to answer your question how to mock a static method: mockito allows this since version 3.8.0. You can find a tutorial here at Baeldung

This allows generating a statically mocked Object for a concrete context, which you can create within a try block. For your case this would look like the following.

Fixed Unit Test

package com.javaeasily.demos.junit;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class MyClassTest {
    private MyClass myclass;

    @BeforeEach
    public void SetUp() {
        try (MockedStatic<NodeUtils> nodeUtilsMockedStatic = Mockito.mockStatic(NodeUtils.class)) {
            nodeUtilsMockedStatic.when(NodeUtils::getMyNode).thenReturn("foo");
            myclass = new MyClass();
        }
    }

    @Test
    public void testReconfigureNode() {
            myclass.reconfigureNode();
    }
}

Mockito dependency

You need mockito with at least version 3.8.0 in your project.

With maven add:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>3.8.0</version>
    <scope>test</scope>
</dependency>

With gradle add:

testImplementation group: 'org.mockito', name: 'mockito-inline', version: '3.8.0'
  • Related