1

I have two simple Consumer components and one Consumer service. Then I want to write unit test for this service. But always got null pointer exception.

I have tried: Autowire construction, Autowire setter, Put mock into test method body, put mock into @Before method, Add/Remove @PrepareForTest({MyService.class}), etc. None of them is working.

Here is my code:

@Component
public class MyComponent1 implements Consumer<Employee> { }

@Component
public class MyComponent2 implements Consumer<Employee> { }

@Service
public class MyService implements Consumer<List<Employee>> {
    @Autowired
    private MyComponent1 myComponent1;
    @Autowired
    private MyComponent2 myComponent2;

    @Override
    public void accept(List<Employee> employeeList) {
        employeeList.forEach(myComponent1.andThen(myComponent2));
    }
}

@SpringBootTest
@ActiveProfiles("test")
@RunWith(SpringRunner.class)
//@PrepareForTest({MyService.class})
public class MyServiceTest {

    @MockBean
    private MyComponent1 mockedComponent1;

    @MockBean
    private MyComponent2 mockedComponent2;

    @Autowired
    private MyService myService;

    @Before
    public void init() {
        PowerMockito.doNothing().when(mockedComponent1).accept(any(Employee.class));
        PowerMockito.doNothing().when(mockedComponent2).accept(any(Employee.class));
    }
    @Test
    public void myTest() {
        Employee employee1 = new Employee("abc", 43);
        List<Employee> employeeList = new LinkedList<>();
        employeeList.add(employee1);

        myService.accept(employeeList);

        verify(mockedComponent1, times(1)).accept(any(Employee.class));
        verify(mockedComponent2, times(1)).accept(any(Employee.class));
    }
}

Error stack

java.lang.NullPointerException
    at java.util.Objects.requireNonNull(Objects.java:203)
    at java.lang.Iterable.forEach(Iterable.java:73)
    at com.wanghongliang.service.MyService.accept(MyService.java:31)
    at com.wanghongliang.service.MyServiceTest.myTest(MyServiceTest.java:54)
    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.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
    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:251)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    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.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:190)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
2
  • Is your issue related to this? Commented Apr 7, 2021 at 2:36
  • Why are you both mocking and providing beans for those 2 types? Commented Apr 7, 2021 at 2:40

1 Answer 1

2

The problem is that in your method under test you call:

myComponent1.andThen(myComponent2)

As myComponent1 is a mock and you haven't stubbed andThen method call, the expression evaluates to null, which you pass to forEach.

Fix 1:

  • create a new mock of Consumer.class. Let's call it combinedConsumer
  • stub myComponent1.andThen to return combinedConsumer

Fix 2:

  • Instruct Mockito to call real method for andThen
Mockito.when(consumer1.andThen(consumer2)).thenCallRealMethod();

More general remarks:

  • You don't need a @SpringBootTest for a single service test. I would opt for MockitoExtension / Runner. Your test will be less fragile and faster, as currently entire spring app context needs to be created.
  • doNothing is the default action for a void method (in your case Consumer.accept). You don't need to stub it.
  • Mockito is enough for this test (nothing PopwerMockito-specific is used)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.