Reputation: 442
I have a unit test I am writing for a class, and this class uses a ConfigurationManager I wrote to get configuration from a TOML object (and therefore from a TOML file).
The Code
Here is the relevant ConfigurationManager code:
public class ConfigurationManager {
// DEFAULT_LOGGING_LEVEL should represent level to use in production environment.
private final static Level DEFAULT_LOGGING_LEVEL = Level.FINE;
private final static String LOG_LEVEL_ENV_PROPERTY = "LOG_LEVEL";
private final static String TOML_FILE_NAME = "config.toml";
private final static String LOCAL_ENV_PROPERTY = "local";
private final static String ENV_PROPERTY = "MY_ENV";
private static Logger CM_LOGGER;
private Environment environment;
public ConfigurationManager() {
environment = new Environment();
CM_LOGGER = new LoggerUtil(ConfigurationManager.class.getName(), getLoggingLevel()).getLogger();
}
public File getTomlFile() throws URISyntaxException, FileNotFoundException {
URI uri = getConfigURI();
File tomlFile = new File(uri);
if (!tomlFile.exists()) {
String err = TOML_FILE_NAME + " does not exist!";
CM_LOGGER.severe(err);
throw new FileNotFoundException(err);
}
return tomlFile;
}
/**
* @return A URI representing the path to the config
* @throws URISyntaxException if getConfigURI encounters bad URI syntax.
*/
private URI getConfigURI() throws URISyntaxException {
return getClass().getClassLoader().getResource(TOML_FILE_NAME).toURI();
}
/**
* Method for getting the app configuration as a toml object.
*
* @return A toml object built from the config.toml file.
* @throws URISyntaxException if getConfigURI encounters bad URI syntax.
* @throws FileNotFoundException if getTomlFile can't find the config.toml file.
*/
public Toml getConfigToml() throws URISyntaxException, FileNotFoundException {
return new Toml().read(getTomlFile());
}
}
And here is the code that calls this Configuration Manager:
public class Listener {
// Initializations
private static final String CONFIG_LISTENER_THREADS = "listenerThreads";
private static final String DEFAULT_LISTENER_THREADS = "1";
/**
* Constructor for getting app properties and initializing executor service with thread pool based on app prop.
*/
@PostConstruct
void init() throws FileNotFoundException, URISyntaxException {
ConfigurationManager configurationManager = new ConfigurationManager();
int listenerThreads = Integer.parseInt(configurationManager.getConfigToml()
.getString(CONFIG_LISTENER_THREADS, DEFAULT_LISTENER_THREADS));
this.executorService = Executors.newFixedThreadPool(listenerThreads);
LOGGER.config("Listener executorService threads: " + listenerThreads);
}
...
}
And here is the test for that code (See comment to see where NPE is triggered):
public class ListenerTests {
@Mock
ConfigurationManager mockCM;
@InjectMocks
Listener listener = new Listener();
@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}
@Test
public void testListener_ShouldInit() throws FileNotFoundException, URISyntaxException {
when(mockCM.getConfigToml().getString(any(), any())).thenReturn("5"); // !!!NPE TRIGGERED BY THIS LINE!!!
listener.init();
verify(mockCM, times(1)).getConfigToml().getString(any(), any());
}
}
The Problem
I get a NullPointerException as follows
java.lang.NullPointerException
at com.bose.source_account_listener.ListenerTests.testListener_ShouldInit(ListenerTests.java:37)
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.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)
I have a guess as to the problem here but I'm not sure how to validate my guess. My guess is that I am mocking the ConfigurationManager, but the mock doesn't know that the ConfigurationManager can generate a TOML file which has a getString method, so I end up getting the NPE. This makes me think that I need a mock TOML for my mock ConfigurationManager, but I am neither certain this is the case or that this is the proper solution.
I am new to Mockito and Java in general so any help would be appreciated.
Upvotes: 0
Views: 2448
Reputation: 5937
You need to mock every bit of your call, not just the full call. mockCM.getConfigToml()
has no mock response, so it returns null, and a toString is invoked on a null object. Your options are to return a non-mocked "Toml" or mock a Toml and then set that up with a when
configuration.
Toml tomlMock = Mockito.mock(Toml.class);
when(mockCM.getConfigToml()).thenReturn(tmolMock);
when(tmolMock.getString(any(), any())).thenReturn("5");
Upvotes: 2
Reputation: 318
You're trying to mock the method of what is returned by calling getConfigToml. That is, you need to mock the object of what should be returned by getConfigToml, and then call getString on that object.
Upvotes: 1