[英]Java Mockito stuck at doReturn of singleton method
我有一個單例課程來幫助我從控制台讀取輸入:
public class IOHelper {
public org.slf4j.Logger logger = Logger.logger;
//JLine
public ConsoleReader cr;
private static IOHelper instance;
private IOHelper(){
{
try {
cr = new ConsoleReader();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static synchronized IOHelper getInstance(){
if (instance == null){
instance = new IOHelper();
}
return instance;
}
我要測試的代碼將其稱為:
String in = IOHelper.getInstance().cr.readLine();
然后我的測試課:
class Test {
private static NetworkCommunicator networkCommunicator;
private static IOHelper ioHelper;
@BeforeAll
static void setUpClass() throws Throwable {
ioHelper = spy(IOHelper.getInstance());
doReturn("1").when(ioHelper).cr.readLine();
networkCommunicator = spy(NetworkCommunicator.class);
doNothing().when(networkCommunicator).connectToServer();
doNothing().when(networkCommunicator).connectToOtherServer();
}
我的測試卡在了doReturn("1").when(ioHelper).cr.readLine();
行,就好像它實際執行了cr.readline();
部分。 我的private native int read0() throws IOException;
指向private native int read0() throws IOException;
在FileInputStream上找到。 注釋表明,如果沒有可用的輸入,它將阻止。 我想替換控制台上的readLine()
方法,因此當CLI要求輸入時,測試可以“偽造”該輸入。
編輯:2個有趣的線程的調用堆棧:
"main@1" prio=5 tid=0x1 nid=NA runnable
java.lang.Thread.State: RUNNABLE
blocks NonBlockingInputStreamThread@1437
at java.io.FileInputStream.read0(FileInputStream.java:-1)
at java.io.FileInputStream.read(FileInputStream.java:207)
at jline.internal.NonBlockingInputStream.read(NonBlockingInputStream.java:166)
- locked <0x67d> (a jline.internal.NonBlockingInputStream)
at jline.internal.NonBlockingInputStream.read(NonBlockingInputStream.java:135)
at jline.internal.NonBlockingInputStream.read(NonBlockingInputStream.java:243)
at jline.internal.InputStreamReader.read(InputStreamReader.java:257)
at jline.internal.InputStreamReader.read(InputStreamReader.java:194)
at jline.console.ConsoleReader.readCharacter(ConsoleReader.java:2147)
at jline.console.ConsoleReader.readCharacter(ConsoleReader.java:2137)
at jline.console.ConsoleReader.readBinding(ConsoleReader.java:2222)
at jline.console.ConsoleReader.readLine(ConsoleReader.java:2463)
at jline.console.ConsoleReader.readLine(ConsoleReader.java:2374)
at jline.console.ConsoleReader.readLine(ConsoleReader.java:2362)
at jline.console.ConsoleReader.readLine(ConsoleReader.java:2350)
at com.mypkg.Test.setUpClass(Test.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1)
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.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:389)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.lambda$invokeBeforeAllMethods$5(ClassTestDescriptor.java:228)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor$$Lambda$162.715378067.execute(Unknown Source:-1)
at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.invokeBeforeAllMethods(ClassTestDescriptor.java:227)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.before(ClassTestDescriptor.java:151)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.before(ClassTestDescriptor.java:61)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$execute$3(HierarchicalTestExecutor.java:80)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$$Lambda$134.398690014.execute(Unknown Source:-1)
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:77)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$null$2(HierarchicalTestExecutor.java:92)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$$Lambda$137.1353170030.accept(Unknown Source:-1)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
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:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
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.platform.engine.support.hierarchical.HierarchicalTestExecutor.lambda$execute$3(HierarchicalTestExecutor.java:92)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor$$Lambda$134.398690014.execute(Unknown Source:-1)
at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:77)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:51)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:43)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:62)
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)
"NonBlockingInputStreamThread@1437" daemon prio=5 tid=0xf nid=NA waiting
java.lang.Thread.State: WAITING
waiting for main@1 to release lock on <0x67d> (a jline.internal.NonBlockingInputStream)
at java.lang.Object.wait(Object.java:-1)
at jline.internal.NonBlockingInputStream.run(NonBlockingInputStream.java:275)
at java.lang.Thread.run(Thread.java:745)
擴展這個問題:我有一些方法向用戶詢問多個輸入(例如,更新某些設置)。 我是否認為最好的方法是將設置重構為帶有參數並僅測試該新方法的方法? 有一種解決方案,當嘗試從ConsoleReader
讀取任何方法時,我可以將一系列字符串傳遞給測試按ConsoleReader
? 我曾考慮過使用Robot
但是如果不是通過測試而不是通過底層的邏輯來進行讀取,那么如何確保以正確的順序傳遞擊鍵呢?
似乎您在嘲笑錯誤的事情。 您想使用ConsoleReader
的收益表。 所以有兩個選擇:
移至在IOHelper
類上使用一些getConsoleReader()
方法,然后可以將其模擬出來-您需要確保IOHelper
類也通過此方法訪問此方法。 例如
private final IOHelper mySpy = spy(IOHelper.getInstance());
@Before
public void setup() {
final ConsoleReader mockCR = mock(ConsoleReader.class);
// Any mockery on your mockCR you need.
// doReturn(...).when(mockCR).readLine();, etc.
doReturn(mockCR).when(mySpy).getConsoleReader();
}
將cr字段修改為模擬。 例如
private final IOHelper ioHelper= IOHelper.getInstance();
@Before
public void setup() {
final ConsoleReader mockCR = mock(ConsoleReader.class);
// Any mockery on your mockCR you need.
// doReturn(...).when(mockCR).readLine();, etc.
ioHelper.cr = mockCR;
}
但是我警告過這種情況。 我看不出將您的ConsoleReader
public
(或不是final
)的理由,而這僅是一項要求。 您可以始終使用一些幫助程序庫來弄亂該字段,即使該字段是私有的也是如此。 spring和apache-commons-lang3均提供此類實用程序。
使用Powermock擺弄ConsoleReader的構造ConsoleReader
:
@RunWith(PowerMockRunner.class)
@PrepareForTest(IOHelper.class)
public class IOHelperTest {
@BeforeClass
public static void setup() {
final ConsoleReader mockCR = mock(ConsoleReader.class);
// Any mockery on your mockCR you need.
// doReturn(...).when(mockCR).readLine();, etc.
PowerMock.whenNew(ConsoleReader.class).thenReturn(mockCR);
}
}
最后,您可以修改IOHelper
類,以將ConsoleReader
用作構造函數參數,並只需通過上述所有方法來提供mockCR
即可(並使其不private
)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.