I'm trying to get rid of PowerMock
and replace it with mockito-inline
new feature Mocking object construction ,
as I can't refactor the old source code.
One of the test classes I have is mocking FileInputStream
,
the class under test FileViewer
import java.awt.Button;
import java.awt.Event;
import java.awt.Font;
import java.awt.TextArea;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class FileViewer extends java.awt.Frame {
private static final long serialVersionUID = 1L;
Button close;
GUIListener fGuiListener;
public FileViewer() {
super();
fGuiListener = new GUIListener();
addWindowListener(fGuiListener);
}
public FileViewer(String filename) throws IOException {
super("FileViewer: " + filename);
fGuiListener = new GUIListener();
addWindowListener(fGuiListener);
File f = new File(filename);
int size = (int) f.length();
int bytes_read = 0;
byte[] data = new byte[size];
try (FileInputStream in = new FileInputStream(f)) {
while (bytes_read < size)
bytes_read += in.read(data, bytes_read, size - bytes_read);
}
TextArea ta = new TextArea(new String(data, 0), 24, 80);
ta.setFont(new Font("Helvetica", Font.PLAIN, 12));
ta.setEditable(false);
this.add("Center", ta);
close = new Button("Close");
this.add("South", close);
this.pack();
this.show();
}
public boolean action(Event e, Object what) {
if (e.target == close) {
this.hide();
this.dispose();
return true;
} else
return false;
}
}
and the original unit test using powermock was
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.FileInputStream;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@PowerMockIgnore({ "javax.management.*", "javax.security.*" })
@RunWith(PowerMockRunner.class)
@PrepareForTest({ FileViewer.class, FileInputStream.class, java.awt.Frame.class })
public class FileViewerTest {
String dir = System.getProperty("user.dir");
String fileName = "/testFiles/testRead.txt";
FileInputStream mockStream = null;
@Before
public void setup() throws Exception {
mockStream = Mockito.mock(FileInputStream.class);
when(mockStream.read(any(byte[].class), anyInt(), anyInt())).thenReturn(2000);
PowerMockito.whenNew(FileInputStream.class).withAnyArguments().thenReturn(mockStream);
}
@Test
public void testFileViewer_wFilename() throws Exception {
FileViewer spy = Mockito.spy(new FileViewer(dir + fileName));
verify(mockStream, times(1)).close();
spy.dispose();
}
}
I tried to follow the example Mock Java Constructors With Mockito | Configuration and Examples and creat a new unit test using MockedConstruction as the following
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.File;
import java.io.FileInputStream;
import org.junit.Test;
import org.mockito.MockedConstruction;
import org.mockito.Mockito;
public class FileViewerMockitoTest {
String dir = System.getProperty("user.dir");
String fileName = "/testFiles/testRead.txt";
@Test
public void testFileViewerWithFilename() throws Exception {
try (MockedConstruction<FileInputStream> mocked = Mockito.mockConstruction(FileInputStream.class,
(mock, context) -> {
// further stubbings ...
when(mock.read(any(), any(), any())).thenReturn((int) new File(dir + fileName).length() + 1);
})) {
FileViewer cut = new FileViewer(dir + fileName);
verify(mocked, times(1)).close();
cut.dispose();
}
}
}
But I got the following Exception
org.mockito.exceptions.base.MockitoException: Could not initialize mocked construction
at java.io.FileInputStream.<init>(FileInputStream.java)
at sun.misc.URLClassPath$FileLoader$1.getInputStream(URLClassPath.java:1385)
at sun.misc.Resource.cachedInputStream(Resource.java:77)
at sun.misc.Resource.getByteBuffer(Resource.java:160)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:455)
at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at com.cds.nrd.xss.util.FileViewerMockitoTest.testFileViewerWithFilename(FileViewerMockitoTest.java:30)
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.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 org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:43)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Iterator.forEachRemaining(Iterator.java:116)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:82)
at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:73)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:137)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: java.lang.NullPointerException
at com.cds.nrd.xss.util.FileViewerMockitoTest.lambda$0(FileViewerMockitoTest.java:27)
at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker$InlineConstructionMockControl.lambda$enable$0(InlineByteBuddyMockMaker.java:710)
at org.mockito.internal.creation.bytebuddy.InlineByteBuddyMockMaker.lambda$new$3(InlineByteBuddyMockMaker.java:272)
at org.mockito.internal.creation.bytebuddy.MockMethodAdvice.handleConstruction(MockMethodAdvice.java:176)
at org.mockito.internal.creation.bytebuddy.inject.MockMethodDispatcher.handleConstruction(MockMethodDispatcher.java:53)
... 57 more
Any idea about the reason of the exception or how to make it work, or any alternate approach?
Found the solution:
We can't set any() parameter in the stub of the lambda function in try-with-resource
(in your case, when(mock.read(any(), any(), any()))
in FileViewerMockitoTest
), which will cause mock.read(any(), any(), any())
to throw an NPE: "could not unbox null" (don't know what it means).
Just simply replace (all of) these arguments to something like any(ArgClass.class)
, will solve the NPE problem, so do with the Could not initialize mocked construction
MockitoException
problem.
(How did I find the problem? By extracting the lambda function as a method, we can get the real description of the NPE in the debug environment.)
(I was surprised that there was no information on the internet other than this question.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With