Why is a void method getting a NullPointerException on a mocked object?
<p>I am writing unit tests for my java app that analyzes commits to Stash, an atlassian app similar to Github. </p>

<p>The method that I am testing is this one:</p>

<pre><code>public List&lt;Message&gt; processEvent(RepositoryRefsChangedEvent event) {
    ArrayList&lt;Message&gt; commitList = new ArrayList&lt;Message&gt;();

    for (RefChange refChange : event.getRefChanges()) {
        LOGGER.info("checking ref change refId={} fromHash={} toHash={} type={}", refChange.getRefId(), refChange.getFromHash(),
                refChange.getToHash(), refChange.getType());

        if (refChange.getRefId().startsWith(REF_BRANCH)) {
            if (refChange.getType() == RefChangeType.ADD &amp;&amp; isDeleted(refChange)) {
                LOGGER.info("Deleted a ref that never existed. This shouldn't ever occur.");
            }
            else if (isDeleted(refChange) || isCreated(refChange)) {
                branchCreation(refChange, event.getRepository(), commitList);
            }
            else {
                sepCommits.findCommitInfo(refChange, event.getRepository(), commitList);
            }
        }
        else {
            refNotProcessed(refChange);
        }
    }
    return commitList;
}
</code></pre>

<p>I am trying to make sure that if I have a git notes commit, the processing is ignored and <code>refNotProcessed(..)</code> is called. </p>

<p>Luckily, I was able to figure this out with relative ease and came to the below solution: </p>

<pre><code>@RunWith (MockitoJUnitRunner.class)
public class RefChangEventTest {
    @Mock RefChange ref;
    @Mock RepositoryRefsChangedEvent refsChangedEvent;
    @Mock Repository repo;
    @Mock ApplicationPropertiesService appService;
    @Mock SEPCommits sepCommits;
    @Spy SEPRefChangeEventImpl sepRefChangeEvent = new SEPRefChangeEventImpl(sepCommits, appService);

    @Before
    public void testSetup() {
        Collection&lt;RefChange&gt; refList = new ArrayList&lt;RefChange&gt;(1);
        refList.add(ref);
        when(refsChangedEvent.getRefChanges()).thenReturn(refList);
        when(refsChangedEvent.getRepository()).thenReturn(repo);
    }

    @Test
    public void gitNotesAreIgnored() throws Exception {
        when(ref.getRefId()).thenReturn("refs/notes/foo");
        when(ref.getFromHash()).thenReturn("da69d7e202d7f66cba01c6f4030bd5975adbf200");
        when(ref.getToHash()).thenReturn("da69d7e202d7f66cba01c6f4030bd5975adbf201");
        doNothing().when(sepCommits).findCommitInfo(any(RefChange.class), any(Repository.class), any(ArrayList.class));

        sepRefChangeEvent.processEvent(refsChangedEvent);
        verify(sepRefChangeEvent, times(1)).refNotProcessed(ref);
    }
</code></pre>

<p>After this, I wanted to see if my unit tests would fail for the right reasons if I changed the ref name to something expected like <code>refs/heads/foo</code>. I'd want to see something along the lines of: <code>expected 1 execution of refNotProcessed but was not run at all</code></p>

<p>Instead I get:</p>

<pre><code>java.lang.NullPointerException
at com.cray.stash.SEPRefChangeEventImpl.processEvent(SEPRefChangeEventImpl.java:62)
at ut.com.isroot.stash.plugin.RefChangEventTest.gitNotesAreIgnored(RefChangEventTest.java:48)
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:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
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:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:117)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:253)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:84)
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:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
</code></pre>

<p>Which points to the call to <code>sepCommits.findCommitInfo(..)</code> By default, methods with void signatures do nothing when a mock calls them. That's exactly what I want it to do. I want it to be called but do nothing but record the fact that <code>sepCommits</code> was interacted with. Why is an NPE happening?</p>

<p>Here are some more methods people are asking for:</p>

<pre><code>public SEPRefChangeEventImpl(SEPCommits sepCommits, ApplicationPropertiesService appService) {
    this.sepCommits = sepCommits;

    try {
        endpoint = appService.getPluginProperty("plugin.fedmsg.events.relay.endpoint");
    } catch (Exception e) {
        LOGGER.error("Failed to retrieve properties\n" + e);
    }

    if (endpoint == null) {
        endpoint = "tcp://some.web.address"
    }
}


public void refNotProcessed(RefChange refChange) {
    LOGGER.info("This type of refChange is not supported.\n refId={} fromHash={} toHash={} type={}", refChange.getRefId(), refChange.getFromHash(),
            refChange.getToHash(), refChange.getType());
}

public void findCommitInfo(RefChange ref, Repository repo, ArrayList&lt;Message&gt; commitList) {
    Page&lt;Commit&gt; commits = getChangeset(repo, ref);
    for (Commit commit : commits.getValues()) {
        String topic = topicPrefix + repo.getProject().getKey() + "." + repo.getName() + ".commit";
        Message message = new Message(getInfo(commit, ref), topic);
        commitList.add(message);
    }
}
</code></pre>