Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerMockito .when().thenReturn() with randomUUID not returning expected value [duplicate]

I'm trying to test a Web Service method which connects to a SQL Server Database which contains JCR nodes, as we're using JackRabbit.

The method looks like:

public String addDocumentByJson(String fileName, byte[] fileContent, int status, String userName, String jsonProperties) {
    UUID id = UUID.randomUUID();
    // It does a bunch of operations here
    return jsonResult;
}

Where jsonResult is an object similar to this one:

{
    "id" : "<A random UUID>"
    "version" : 1
}

Now, when I try to test it following the steps in this answer and the code in this post and I came off with the following code (which as I said is based on the past links):

@PrepareForTest({ UUID.class })
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/TestSpringConfig.xml")
public class TestJackRabbitService {

    @Autowired
    @Qualifier("jackRabbitService")
    IJackRabbitService jackRabbitService;

    private byte[] fileContent;
    private int versionFile;

    public TestJackRabbitService() {
        classLoader = getClass().getClassLoader();
    }
    @BeforeClass
    public static void init() {
        LOG.trace("Run @BeforeClass");
        try {
            fileContent = IOUtils.toByteArray(new FileInputStream(new File(Thread.currentThread().getContextClassLoader().getResource("fileTest.txt"))));
        } catch (Exception e) {
            LOG.error(ExceptionUtils.getStackTrace(e));
        }
    }

    @Before
    public void before() {
        LOG.trace("Run @Before");
        try {
            versionFile = jackRabbitService.getLastVersionOf(nameApp, nameFile); //This method returns an int,
        } catch (Exception e) {
            LOG.error(ExceptionUtils.getStackTrace(e));
        }
    }

    @Test
    public void testAddDocumentsByJson() {
        //Some tests which run correctly

        final UUID uuid = UUID.randomUUID();
        mockStatic(UUID.class);
        LOG.debug(uuid);
        //doReturn(uuid).when(UUID.randomUUID());
        when(UUID.randomUUID()).thenReturn(uuid);
        idFile = uuid;

        assertEquals(jackRabbitService.addDocumentByJson(nameFile, bytes, nameApp, 5, jsonproperties), "{\"id\":\"" + uuid + "\",\"version\":1}");
    }
}

However when I test this method it gives me the following results:

Results :

Failed tests: 
    testAddDocumentsByJson(com.optimissa.test.junit.TestJackRabbitService): expected:<{"id":"[1efaf3b8-ca7c-4e6f-878f-102d9a7a92d9]","version":1}> but was:<{"id":"[cfa1a8b0-be6a-46b1-90f5-d2f6d230796a]","version":1}>

As you can see both UUIDs are different, and from what I read on my first link in this question is that it should return the same UUID everytime the static method UUID.randomUUID() is called (the one stored in the uuid variable inside the TestJackRabbitService class...

I also tried with doReturn method as explained in this answer but it produces the following stack trace:

testAddDocumentsByJson(com.optimissa.test.junit.TestJackRabbitService)  Time elapsed: 5.279 sec  <<< ERROR!
org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at com.optimissa.test.junit.TestJackRabbitService.testAddDocumentsByJson(TestJackRabbitService.java:143)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, which is not supported
 3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed

    at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:182)
    at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:164)
    at org.powermock.core.MockGateway.methodCall(MockGateway.java:134)
    at com.optimissa.test.junit.TestJackRabbitService.testAddDocumentsByJson(TestJackRabbitService.java:143)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
    at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner$2.call(DelegatingPowerMockRunner.java:149)
    at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner$2.call(DelegatingPowerMockRunner.java:141)
    at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner.withContextClassLoader(DelegatingPowerMockRunner.java:132)
    at org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner.run(DelegatingPowerMockRunner.java:141)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:57)
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)

From this answer I read (but I don't understand) that maybe I need to create a new object from the class I'm trying to test? I'm injecting the dependency at the very beginning of the test class, I'm really new to JUnit testing and english is not my native language, however I can comprehend most of thing but that answer is giving me a hard time understanding it (due to my lack of knowledge in JUnit testing).

How can I make my JUnit test to retrieve the same ID which is generated inside the method (or intercept the call to UUID.randomUUD() to return the value inside my JUnit test) ?


Edit

After trying @hammerfest's answer, with the following changes:

UUID uuid = PowerMockito.mock(UUID.class);

mockStatic(UUID.class);
when(UUID.randomUUID()).thenReturn(uuid);

String jsonToCompare = "{\"id\":\"" + uuid + "\",\"version\":1}";
String jsonFromJRS = jackRabbitService.addDocumentByJson(nameFile, bytes, nameApp, 5, jsonproperties);

assertEquals(jsonFromJRS, jsonToCompare);

I still get this result:

testAddDocumentsByJson(com.optimissa.test.junit.TestJackRabbitService): expected:<{"id":"[493410b3-dd0b-4b78-97bf-289f50f6e74f]","version":1}> but was:<{"id":"[00000000-0000-0000-0000-000000000000]","version":1}>
like image 950
Frakcool Avatar asked Jun 29 '17 15:06

Frakcool


1 Answers

Common mistake with mocking system classes it's that they are added to @PrepareForTest, but unfortunately it's impossible to mock final Java System classes directly. But PowerMock provides workaround. PowerMock replaces calls to system classes by call to PowerMock class. A class that use final system class should be added to @PrepareForTest

I've added example how to mock UUID.

public class DocumentService {

  public JsonDocument saveDocument(JsonDocument document){
    UUID uuid = UUID.randomUUID();
    document.setId(uuid.toString());
    return document;
  }
}

Test

@RunWith(PowerMockRunner.class)
@PrepareForTest(DocumentService.class)
public class DocumentServiceTest {
@Test
public void should_set_id() throws Exception {
    final String id = "493410b3-dd0b-4b78-97bf-289f50f6e74f";
    UUID uuid = UUID.fromString(id);

    mockStatic(UUID.class);
    when(UUID.randomUUID()).thenReturn(uuid);

    DocumentService documentService = new DocumentService();

    JsonDocument document = new JsonDocument();
    documentService.saveDocument(document);

    assertThat(document.getId())
        .as("Id is set")
        .isEqualTo(id);
  }
}

You may find more in documentation.

like image 110
Arthur Zagretdinov Avatar answered Nov 14 '22 23:11

Arthur Zagretdinov