-2

NOTE - I've marked 3 LINE numbers which I discuss in my question, you may need to scroll to the right in the code snippets to see.

I'm really struggling unit testing a method with chained Optional.map()s.

@Override
public void accept(Object message)
{
    extractSenderReference(message.toString())
        .map(t ->
        {
            t.setTransactionStatus("TAG1"); //  <- LINE #1
            return t;
        })
        .map(StaticConverter::convert) //< -LINE #2
        .ifPresent(Persist::persist);
}

Where extractSenderReference() returns an Optional of type Obj and is a private method.

And my test:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassBeingTested.class, StaticConverter.class})

public class MyTest {

private ClassBeingTested updateProcessor = PowerMockito.spy(new ClassBeingTested());
private StatusDataObj statusDataObj = mock(StatusDataObj.class);

@Test
public void testSomething() throws Exception{
    Obj myObj = getObj();
    PowerMockito.mockStatic(StaticConverter.class);

    PowerMockito.doReturn(Optional.ofNullable(myObj)).when(updateProcessor, "extractSenderReference", anyString()); // <- LINE #3
    when(StaticConverter.convert(myObj)).thenReturn(statusDataObj);
    updateProcessor.accept("MESSAGE1");
}

private Obj getObj(){
    Obj obj = new Obj();
    obj.setId(100L);
    return obj;
 }
}

At LINE #1, as marked in my accept() method, object t has been processed and has had its transactionStatus set successfully. However at LINE #2 I am getting a NPE when running the above test.

I've also tried PowerMockito.spy(StaticConverter.class); instead of PowerMockito.mockStatic(StaticConverter.class); as per https://github.com/powermock/powermock/wiki/Mockito#mocking-static-method but I'm getting the same NPE.

My thinking was map is converting t to StatusDataObj type. So when map calls convert, I'll stub and return my type. However, originally I was expecting that LINE #3 would effectively take care of the chained map calls on the Optional returned from extractSenderReference(), since I'm using a real object with values set, but there must be a null value somewhere else?

notAChance
  • 1,360
  • 4
  • 15
  • 47
  • Could your code by any chance be presented as [a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve), please? When I try to read through it, I feel there are quite many unknowns. – Ole V.V. Jan 29 '19 at 14:01
  • Does `Obj` implement `equals` (and `hashCode`) correctly? If not, I suspect it might stand a better chance of working if you store `getObj()` in a variable, and use it in both places. – Andy Turner Jan 29 '19 at 14:03
  • @AndyTurner good shout but unfortunately the same outcome. I've updated the snippets to reflect the change. – notAChance Jan 29 '19 at 14:11
  • 1
    @OleV.V. I've removed some method calls and replaced with return types to simplify. – notAChance Jan 29 '19 at 14:14
  • Can you show how you annotated the Test Class? – Maciej Kowalski Jan 29 '19 at 14:30
  • @MaciejKowalski Updated. I have included `@PrepareForTest({ClassBeingTested.class, StaticConverter.class})` in my code, if this is what you're after :) – notAChance Jan 29 '19 at 14:33
  • Try replacing the method reference `StaticConverter::convert` with an explicit lambda call to the actual method: `e -> StaticConverter.convert(e)`. – nickb Jan 30 '19 at 15:14

3 Answers3

1

Try replacing the method reference StaticConverter::convert with an explicit lambda call to the actual method: e -> StaticConverter.convert(e).

I've had issues with Powermock mocking method references, but by leaving it as an explicit method call I could successfully mock those calls.

nickb
  • 59,313
  • 13
  • 108
  • 143
0

You need to add the classes to the @PrepareForTest with which you will be working in that test:

@RunWith(PowerMockRunner.class)
@PrepareForTest(StaticConverter.class, ClassBeingTested.class)

Powermock needs to be aware you will be using it for these classes.

Maciej Kowalski
  • 25,605
  • 12
  • 54
  • 63
0

Persist was null. I'm not sure why the NPE was at LINE 2.

notAChance
  • 1,360
  • 4
  • 15
  • 47