简体   繁体   中英

Mockito NullPointerException thrown instead of custom ExitException

I'm trying to test the functionality of my ApplicationRunner class which currently depends on a simple CLI class. Using mockito, i'm attempting to mock the CLI and determine the conditions on which a custom ExitException is thrown. (when the CLI s help() method is shown). My issue is that the test is throwing a NullPointerException rather than an ExitException when it his the parse function.

Test code:

public class ApplicationRunnerTest {

@Mock
private APUCLI cli;

private ApplicationRunner runner;

@Before
public void prepareDependencies(){
    MockitoAnnotations.initMocks(this);
    runner = new ApplicationRunner();
}


@Test(expected = ExitException.class)
public void verifyHelpOptionsRun() throws Exception{
    String[] args = new String[]{};

    runner.run(args);

    when(cli.parse(args)).thenReturn(null);

    verify(cli, times(1)).parse(args);
    verify(cli, times(1)).help();
}

}

The cli class which is mocked:

@Component("Cli")
public class APUCLI implements CLI {


@Override
public ParsedArgs parse(String args[]) {
    System.out.println("Parsing CLI");
    return null;
}

@Override
public void help() throws ExitException{
    System.out.println("something");
    throw new ExitException(1);
}
}

The APU Runner code.

@Component("Runner")
public class ApplicationRunner implements APURunner{

@Inject
@Named("Cli")
private CLI commandLineInterface;

@Override
public void run(String[] args) throws ExitException{
    ParsedArgs parsedArgs = getParsedArgs(args);
    if(parsedArgs == null){
        callHelp();
    }

    System.out.println("Running");

}

private ParsedArgs getParsedArgs(String[] args){
    return commandLineInterface.parse(args);
}

private void callHelp() throws ExitException{
    commandLineInterface.help();
}
}

The error:

java.lang.Exception: Unexpected exception, expected<Systems.biology.laboratory.ExitException> but was<java.lang.NullPointerException>

at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:28)
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: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)
Caused by: java.lang.NullPointerException
at Systems.biology.laboratory.runners.ApplicationRunner.getParsedArgs(ApplicationRunner.java:33)
at Systems.biology.laboratory.runners.ApplicationRunner.run(ApplicationRunner.java:23)
at Systems.biology.laboratory.runners.ApplicationRunnerTest.verifyHelpOptionsRun(ApplicationRunnerTest.java:32)
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.ExpectException.evaluate(ExpectException.java:19)
... 15 more

You have two issues (at least) :

1) You mock a APUCLI instance :

@Mock
private APUCLI cli;

But you never set it to the ApplicationRununer instance under test. So the APUCLI field defined in the ApplicationRununer instance is null .

You could provide a constructor that allows to set the dependency.

So you could replace :

@Inject
@Named("Cli")
private CLI commandLineInterface;

by :

private CLI commandLineInterface;

@Inject
public ApplicationRunner(CLI commandLineInterface){
     this.commandLineInterface = commandLineInterface;
}

You could so create it in this way :

@Before
public void prepareDependencies(){
    MockitoAnnotations.initMocks(this);
    runner = new ApplicationRunner(cli);
}

About the @Named qualifier, sorry I am not sure about the way to specify it in a autowired constructor with a javax Inject annotation.
So I prefer put this point aside.

2) You set the mock behavior after executing the method to test. It is too late.It should be done before if you want that it be considered during the execution of the method to test.

@Test(expected = ExitException.class)
public void verifyHelpOptionsRun() throws Exception{
    String[] args = new String[]{};

    // mock record first
    when(cli.parse(args)).thenReturn(null); 

    // execute the method to test
    runner.run(args);        

    // do some checks (if required)
    verify(cli, times(1)).parse(args);
    verify(cli, times(1)).help();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM