1

I am getting 3 errors below when trying to mock New Date, using PrepareForTest. How can I fix this?

Reference: https://stackoverflow.com/a/30415404/15435022

java.lang.NoClassDefFoundError: org/powermock/tests/utils/ArrayMerger at org.powermock.api.mockito.PowerMockito.whenNew(PowerMockito.java:506)

Code below.

import static org.powermock.api.mockito.PowerMockito.whenNew;
import static org.mockito.BDDMockito.given;

@PrepareForTest({ Product.class })
public class ProductTest {
    ....
    Calendar calendar = Calendar.getInstance();
    calendar.set(2022, 5, 2, 1, 1, 1);
    Date currentDate =  calendar.getTime();
    whenNew(Date.class).withNoArguments().thenReturn(currentDate);

POM:

    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-module-junit4-rule</artifactId>
        <version>1.4.11</version>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>*</groupId>
                <artifactId>*</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-api-mockito</artifactId>
        <version>1.4.11</version>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>*</groupId>
                <artifactId>*</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.powermock</groupId>
        <artifactId>powermock-api-support</artifactId>
        <version>1.4.11</version>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>*</groupId>
                <artifactId>*</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
mattsmith5
  • 540
  • 4
  • 29
  • 67

2 Answers2

1

Let me get this straight: you're excluding all transitive dependencies, and then complaining that classes cannot be found at runtime?

ArrayMerger happens to come from mockito-core, which is bound to be one of the transitive dependencies you're excluding.

crizzis
  • 9,978
  • 2
  • 28
  • 47
1

Exclusions in Maven dependencies are used to prevent certain transitive dependencies from being included in the project.
It can help to prevent dependency conflicts, or classpath issues.

However, using wildcards to exclude all transitive dependencies, as shown in the original POM file:

<exclusions>
    <exclusion>
        <groupId>*</groupId>
        <artifactId>*</artifactId>
    </exclusion>
</exclusions>

is generally not recommended, as it can lead to unexpected issues such as missing classes and compatibility problems, and would explain the NoClassDefFoundError you are encountering (java.lang.NoClassDefFoundError: org/powermock/tests/utils/ArrayMerger).

When using exclusions, it is best to be explicit and selective about which dependencies you are excluding, and to understand why you are excluding them. If you are not sure why an exclusion is needed, it is usually best to not include it, especially for testing libraries like PowerMock, which often have necessary transitive dependencies.

Consider also using the latest version (2.0.9) of powermock (2019), instead of 1.4.11 (pre-2017).

Finally, in your test class, you are using @PrepareForTest({ Product.class }). However, you are trying to mock the creation of a new Date object. You need to prepare the class that calls the new Date() constructor. This should be the class containing the code you are testing, not necessarily Product.class.

Your test class and POM file, with some of these suggestions, would look like:

Test Class:

import static org.powermock.api.mockito.PowerMockito.whenNew;
import static org.mockito.BDDMockito.given;

import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ ClassContainingNewDateCall.class }) // Replace with the class that calls new Date()
public class ProductTest {
    // ... rest of your code
}

POM:

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.9</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.9</version>
    <scope>test</scope>
</dependency>

You will need to replace ClassContainingNewDateCall.class with the actual class that calls the new Date() constructor in your code.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250