I have a class which holds a single predicate function:
@RequiredArgsConstructor
public class IsSampleTrue implements SamplePredicateFactory {
private final SampleValueCalculator sampleValCalc;
private final SampleParameterManager<SampleParameter> sampleParameterMgr;
private final Cache<String, SampleData> sampleCache;
@Override
public SamplePredicate buildSamplePredicate(SampleContext ctx) {
// if ctx is missing the premade MainObj then we create our own manually
MainObject mainObj = ctx.getMainObject.orElseGet(() -> {
return MainObject.builder()
.a(ctx.getA())
.b(ctx.getB())
.c(ctx.getC())
.build();
}
);
SampleValueObject sampleValueObj = sampleValueCalc.calcSampleValue(mainObj);
double sampleValueX = sampleValueObj.getSampleValueX(); // get NullPointerException here
if (sampleValueX > 100) {
return sample -> false;
}
return sample -> {
if (...) {
return false;
}
return true;
}
}
}
Implementation of calcSampleValue()
method in SampleValueCalculator
class:
@RequiredArgsConstructor
public class SampleValueCalculator {
private final SampleParameterManager sampleParameterManager;
public SampleValueObject calcSampleValue(MainObj mainObj) {
return SampleValueObject.builder()
.sampleValueA(mainObj.getA() * sampleParameterManager.getParameter(SampleParameter.VALUE_A_FACTOR))
.sampleValueB(mainObj.getB())
.sampleValueC(mainObj.getC())
.build();
}
}
Now I have a unit test to test this class:
public class IsSampleTrueTest {
private static final double SAMPLE_CONSTANT = 0.1;
@Mock
private SampleValueCalculator sampleValCalc;
@Mock
private SampleParameterManager sampleParameterManager;
@Mock
private Cache<String, SampleData> sampleCache;
@Mock
private SampleContext ctx;
@Mock
private MainObj mainObj;
private IsSampleTrue predicateFunc;
@Before
public void before() {
MockitoAnnotations.initMocks(this);
when(sampleParameterManager.getParameter(SampleParameter.SAMPLE_CONSTANT_VALUE)).thenReturn(SAMPLE_CONSTANT);
when(ctx.getC()).thenReturn(c);
predicateFunc = new IsSampleTrue(sampleValCalc, sampleParameterManager, sampleCache);
}
@Test
public void testMainObjAbsentFromContext() {
SampleData abcd = mock(SampleData.class);
when(sampleCache.get("abcd")).thenReturn(Optional.of(abcd));
when(abcd.getSomeValue()).thenReturn(1.0);
when(ctx.getMainObj()).thenReturn(Optional.empty());
when(ctx.getA()).thenReturn("a");
when(ctx.getB()).thenReturn("b");
when(ctx.getC()).thenReturn("c");
Sample s1 = setupSample(...);
SampleValueObject sampleValueObj = SampleValueObject.builder()
.sampleValueA(1.0)
.build();
when(sampleValueCalc.calcSampleValue(mainObj)).thenReturn(sampleValueObj);
SamplePredicate samplePred = predicateFunc.buildSamplePredicate(ctx); // get NullPointerException here
assertTrue(samplePred.test(sample));
}
@Test
public void testMainObjPresent() {
SampleData abcd = mock(SampleData.class);
when(sampleCache.get("abcd")).thenReturn(Optional.of(abcd));
when(abcd.getSomeValue()).thenReturn(1.0);
when(ctx.getMainObj()).thenReturn(Optional.of(mainObj));
Sample s1 = setupSample(...);
SampleValueObject sampleValueObj = SampleValueObject.builder()
.sampleValueA(1.0)
.build();
when(sampleValueCalc.calcSampleValue(mainObj)).thenReturn(sampleValueObj);
SamplePredicate samplePred = predicateFunc.buildSamplePredicate(ctx);
assertTrue(samplePred.test(sample));
}
}
When I run testMainObjAbsentFromContext()
, I'm getting a NullPointerException
:
java.lang.NullPointerException
at com.package.sample.IsSampleTrue.buildSamplePredicate(IsSamplePredicate.java:21)
at com.package.IsSampleTrueTest.testMainObjAbsentFromContext(IsSampleTruePredicateTest.java:42)
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:52)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
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.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
I've commented next to the lines where I'm getting the NullException
. I'm not super familiar with how Mockito works so any pointers would be appreciated. The unit tests where I have ctx.getMainObj()
returns the premade MainObj
such as testMainObjPresent()
are passing.
Your
when(sampleValueCalc.calcSampleValue(mainObj)).thenReturn(sampleValueObj);
will not be triggered, because you don't passmainObj
-- you pass theMainObject
you create inbuildSamplePredicate
.You can either use
when(sampleValueCalc.calcSampleValue(any(MainObject.class)).thenReturn(sampleValueObj);
or create aMainObjectFactory
class and pass a mock implementation of that into the IsSampleTrue constructor, so that you can stub it to supply a knownMainObject
instance.testMainObjPresent()
works because in that case your mocked context returns theMainObject
instance created in the test.