- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个单例类来帮助我从控制台读取输入:
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();
部分一样。我的堆栈跟踪指向在 FileInputStream 上找到的方法 private native int read0() throws IOException;
。评论表明,如果没有可用的输入,它会阻塞。我想替换控制台上的方法 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 读取时,我可以将一系列字符串传递给测试以按下?我想过使用 Robot
但如果读取不是由测试而不是底层逻辑完成,我如何确保它以正确的顺序传递击键?
最佳答案
看来你在 mock 错误的事情。您想要使用 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
),而这只是一个要求。即使它是私有(private)的,您始终可以使用一些辅助库来扰乱该字段。 spring 和 apache-commons-lang3 都提供这种类型的实用程序。
使用Powermock来摆弄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
)。
关于Java Mockito 卡在单例方法的 doReturn 处,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46889859/
我一直面临一个奇怪的问题。基本上,当我正常运行 Mockito 测试时,即“作为 Junit 测试运行”时,它给了我以下错误。有人可以帮助我请问我的错误是什么? 收到的错误: java.lan
我正在使用 Mockito 以及 mockito-inline用于模拟静态方法。我正在尝试申请 doNothing或类似的行为,到静态 void 方法。以下解决方法有效,但我认为应该有一种更方便的方法
我正在尝试验证我正在测试的类是否调用了正确的依赖类的方法。所以我试图匹配方法参数,但我并不真正关心这个测试中的实际值,因为我不想让我的测试变得脆弱。 但是,我在设置它时遇到了麻烦,因为 Mockito
我正在使用 Mockito 编写单元测试,并且在模拟注入(inject)的类时遇到问题。问题是两个注入(inject)的类是相同的类型,仅通过它们的 @Qualifier 注释进行区分。如果我尝试简单
在我的断言中的以下简单练习中,我期望 1,但得到 0。为什么我会看到这种行为? public class MockitoTest { POJO mockedPojo; @Before
我正在创建一个通用模拟客户端来测试 HTTP 交互。为此,我希望能够以相同的方法进行多次响应。使用普通模拟,这不是问题: when(mock.execute(any(), any(), any()))
我需要全局模拟类方法。 我的意思是,我不能创建模拟对象和 stub 方法。我的 api 不将此对象作为参数,所以我不能在函数调用中传递它,但是这个类的对象是在这些函数中创建并在那里使用的。这就是为什么
我正在尝试使用 Mockito 2.18.3 框架模拟我们公司内部库中提供的 final 类,不幸的是我们无权更改库中的代码。但每当我运行时,我都会收到以下错误: java.lang.NoClassD
研究了mockito测试框架,学习了powermock,突然发现一个叫powermockito的框架,看不懂了。 谁能告诉我这三个测试工具的区别? 最佳答案 Mockito 是市场标准模拟框架,味道非
我想跳过检查验证调用中的参数之一。因此对于: def allowMockitoVerify=Mockito.verify(msg,atLeastOnce()).handle(1st param,,3r
为了模拟在被测方法内部构造的本地对象上的局部变量/方法调用,我们目前使用的是 PowerMockito 库。 我们正在尝试评估是否可以使用 mockito-inline(版本 3.7.7)来做同样的事
我在想, 如果在 @Before 方法中我正在初始化模拟对象,我不应该在 @After 中取消对它的引用吗?或者那会是多余的吗?为什么? 最佳答案 不需要,JUnit 会为每个测试方法创建一个新的测试
我想使用 Mockito 验证字符串参数是否满足两个条件: verify(mockClass).doSomething(Matchers.startsWith("prefix")); verify(m
如果我像这样创建一个模拟 when(servicesTestEnv.mockUserProfileAndPortfolioTransactionRepository.get(servicesTestE
使用 Mockito 我遇到了以下问题: Mockito.when(restOperationMock.exchange( Mockito.anyString(), M
我想知道描述中的事情是否可行以及如何去做。 我知道你可以调用原始方法然后像这样做答案: when(presenter, "myMethod").doAnswer() 但我想对它们进行不同的排序,首先执
我试图弄清楚org.mockito.AdditionalMatchers是如何工作的,但我失败了。为什么这个测试失败了? import static org.hamcrest.CoreMatchers
有人知道使用 Mockito 为 ATG 编写单元测试用例吗?我在凝视时遇到了以下讨论 - Automated unit tests for ATG development和 Using PowerM
我想知道描述中的事情是否可行以及如何去做。 我知道你可以调用原始方法然后像这样做答案: when(presenter, "myMethod").doAnswer() 但我想对它们进行不同的排序,首先执
我有以下接口(interface)CatalogVersionService,它公开了一些服务。我还有一个单元测试,它通过使用 Mockito 来模拟这个接口(interface),如下所示: Cat
我是一名优秀的程序员,十分优秀!