- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试通过将字符串从一个线程发送到另一个线程来测试套接字连接,其中服务器和客户端套接字使用 Mockito v1.9.5 模拟。
这是我要运行的测试:
@Test
public void testConnection() {
//associate a mock server socket with the TCP Connection
TcpSocketConnection connection = new TcpSocketConnection(mockServerSocket);
try {
//begin thread which listens for clients, then sends "Hello, world" to a connected
//client.
connection.listen();
BufferedReader reader = new BufferedReader(
new InputStreamReader(mockTestClientSocket.getInputStream(), DEFAULT_CHARSET)
);
long startTime = System.nanoTime();
for (long interval = 0;
interval < TIMEOUT_TIME;
interval = System.nanoTime() - startTime) {
if (reader.ready()) {
String receivedMessage = reader.readLine();
assertEquals("Hello, world!", receivedMessage);
mockTestClientSocket.close();
connection.closeSocket();
return;
}
}
mockTestClientSocket.close();
connection.closeSocket();
fail("Failed to receive message.");
} catch (IOException e) {
fail(e.getMessage());
}
}
测试一直运行到 TIMEOUT_TIME
,然后失败的断言是 “Failed to receive message.”
我在这里指定模拟对象的行为:
@Before
public void setup() {
mockServerSocket = mock(ServerSocket.class);
try {
when(mockServerSocket.accept()).thenReturn(mockTestClientSocket);
} catch (IOException e) {
fail(e.getMessage());
}
mockTestClientSocket = mock(Socket.class);
try {
PipedOutputStream oStream = new PipedOutputStream();
when(mockTestClientSocket.getOutputStream()).thenReturn(oStream);
PipedInputStream iStream = new PipedInputStream(oStream);
when(mockTestClientSocket.getInputStream()).thenReturn(iStream);
when(mockTestClientSocket.isClosed()).thenReturn(false);
} catch (IOException e) {
fail(e.getMessage());
}
}
我要测试的部分内容是在 connection.listen()
中启动的内部类中的以下 run()
:
class InnerListenerClass implements Runnable {
@Override
public void run() {
try {
clientSocket = socket.accept();
writer = new OutputStreamWriter(
clientSocket.getOutputStream(), DEFAULT_CHARSETNAME);
out = new PrintWriter(writer, true);
while (!clientSocket.isClosed()) {
out.println("Hello, world!");
Thread.sleep(MILLIS_BETWEEN_MESSAGES);
}
} catch (InterruptedException | IOException e) {
LOG.debug(e.getMessage());
}
}
public InnerListenerClass(final ServerSocket socket) {
this.socket = socket;
}
}
下面是 TcpSocketConnection.java
的一部分:
class TcpSocketConnection() {
public TcpSocketConnection(final ServerSocket serverSocket) {
checkNotNull(serverSocket);
this.serverSocket = serverSocket;
}
...
public final void listen() throws IOException {
listenerThread = new Thread(new InnerListenerClass(serverSocket));
listenerThread.start();
}
...
}
我将尝试逐步完成我的测试过程,为这个问题添加一些额外的上下文。从 testConnection()
的开头开始:
TcpSocketConnection connection = new TcpSocketConnection(mockServerSocket);
这将创建一个与与之关联的模拟 ServerSocket 的连接。这将创建一个线程,该线程以以下行开始:
clientSocket = socket.accept();
由于上面的 socket
是对 mockServerSocket
的引用,Mockito 知道返回对名为 mockTestClientSocket
的模拟 Socket 的引用,因为这一行:
when(mockServerSocket.accept()).thenReturn(mockTestClientSocket);
接下来是下面一行:注意:我相信这是我的理解和现实存在分歧的地方,因为我相信基于调试,这个线程在创建这个 OutputStreamWriter 对象时挂起。我还没弄明白为什么。
writer = new OutputStreamWriter(clientSocket.getOutputStream(), DEFAULT_CHARSETNAME);
在给定 OutputStream
的情况下创建一个新的 OutputStreamWriter
。由于 setup
部分中的这些行,Mockito 知道模拟客户端套接字的输出流应该是什么样子:
PipedOutputStream oStream = new PipedOutputStream();
when(mockTestClientSocket.getOutputStream()).thenReturn(oStream);
另外,因为 setup
发生在测试之前,我们知道我们的 InputStream 有一个对这个 OutputStream 的引用,因为这一行:
PipedInputStream iStream = new PipedInputStream(oStream);
根据此构造函数的文档,此 “创建了一个 PipedInputStream,以便它连接到管道输出流 (oStream)。然后写入 (oStream) 的数据字节将可用作此流的输入。 "
run()
中的 while 循环开始并导致“Hello, world!”被发送出 OutputStream(也被 InputStream 接收)。接下来,我们很好地包装 inputStream:
BufferedReader reader = new BufferedReader(new InputStreamReader(mockTestClientSocket.getInputStream(), DEFAULT_CHARSET));
借助 Mockito 的魔力,mockTestClientSocket.getInputStream()
调用实际上返回了之前的 iStream
,因为以下行:
when(mockTestClientSocket.getInputStream()).thenReturn(iStream);
所以现在我们有一个带有输入流的阅读器,并且该输入流连接到一个输出流。该输出流连接到 PrintWriter
,它正在 println
ing “Hello,world!”。然而,读者似乎从来没有得到 ready()
。
为什么创建的监听器线程在创建 OutputStreamWriter
期间挂起,以及我的 Hello, World!
字符串如何从模拟套接字正确发送到模拟套接字客户?
抱歉,我是 Mockito/java.net.* 的新手,总体来说有点厚。我想我已经包含了代码的所有相关部分,但如果有任何不清楚的地方,请告诉我。
最佳答案
我可以通过修改您代码中的两处来使您的单元测试通过:
mockServerSocket.accept()
到目前为止,你 mock mockServerSocket.accept()
太早了,因为 mockTestClientSocket
还没有设置,所以它会返回 null
,你需要先设置它,这样你的代码应该是:
mockServerSocket = mock(ServerSocket.class);
// Set it first
mockTestClientSocket = mock(Socket.class);
try {
// Then mock it
when(mockServerSocket.accept()).thenReturn(mockTestClientSocket);
} catch (IOException e) {
fail(e.getMessage());
}
...
当您启动一个专用线程来管理您的客户端套接字时,您需要同步您的线程以确保您的消息准备好被读取。
为此,您可以:
reader.readLine()
来简化您的代码,但这是一种阻塞方法,因为您的当前线程将等待另一个线程需要的时间写这行(这里的消息)。代码可以是:
BufferedReader reader = ...
String receivedMessage = reader.readLine();
assertEquals("Hello, world!", receivedMessage);
mockTestClientSocket.close();
connection.closeSocket();
TIMEOUT_TIME
设置一个足够大甚至过大的值以确保其他线程准备就绪,例如,因为它是一个以纳秒为单位的值,您可以将它设置为 30
秒到 30_000_000_000L
。如果您没有设置足够大的值,您的测试在缓慢和/或过载和/或共享系统(例如用于持续集成的服务器)中可能会不稳定。关于java - 使用 Mockito 模拟服务器-客户端连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40414930/
我一直面临一个奇怪的问题。基本上,当我正常运行 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
我是一名优秀的程序员,十分优秀!