如何在 Citrus 中测试套接字服务器?
How to test a socket server in Citrus?
我想对使用 Netty 构建的套接字服务器进行一些单元测试。
Socket Server有如下简单代码:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class SocketServer implements Runnable {
private int port;
private EventLoopGroup bossGroup;
private EventLoopGroup workerGroup;
private ChannelFuture channelFuture;
private ServerBootstrap bootstrap;
public SocketServer(int port) {
this.port = port;
this.bossGroup = new NioEventLoopGroup();
this.workerGroup = new NioEventLoopGroup();
}
public int getPort() {
return port;
}
@Override
public void run() {
try {
bootstrap = new ServerBootstrap();
bootstrap
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline()
.addLast(new ReceiveMessageServerHandler())
.addLast(new ParseMessageServerHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
// Bind and start to accept incoming connections.
channelFuture = bootstrap.bind(port).sync();
// Wait until the server socket is closed
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public void shutdown() throws InterruptedException {
channelFuture.channel().close();
}
}
在 MessageHandlers 上,我首先收到由“\n”分隔的短信。我非常需要一个 telnet 客户端。
我想测试我是否可以向服务器发送不同的消息,以及我是否会在一个时间范围内收到某些预期的响应。
我尝试使用 Citrus Framework,但我无法获得任何结果,因为它没有提供适当的纯文本协议(我尝试过 Rest、Soap 等,但它们对我没有好处)。我在 Citrus Reference 2.4 中找不到答案。
我在 post 问题之前解决了问题(我昨天写了问题,但直到今天我才 post ......我找到了答案) .
所以我终于可以用 Citrus Framework 和 Spring Integration 解决这个问题。
与同事一起阅读后,我能够使用 Spring 集成 TCP 适配器作为 Citrus 端点的通道(来自 java.nio 的 SocketChannel)。
Spring Integration Reference - IP
在这里你可能会看到我使用的citrus-context.xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:citrus="http://www.citrusframework.org/schema/config"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.citrusframework.org/schema/config http://www.citrusframework.org/schema/config/citrus-config.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd">
<citrus:channel-endpoint id="citrusServiceEndpoint"
channel-name="input" />
<int-ip:tcp-connection-factory id="client"
type="client" host="localhost" port="9123" single-use="true"
so-timeout="10000" using-nio="true" />
<int:channel id="input" />
<int-ip:tcp-outbound-channel-adapter
id="outboundClient" channel="input" connection-factory="client" />
</beans>
在我的 Citrus 测试中,我能够根据需要发送消息:
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.consol.citrus.TestCaseMetaInfo.Status;
import com.consol.citrus.annotations.CitrusTest;
import com.consol.citrus.dsl.junit.JUnit4CitrusTestDesigner;
public class MyFirstTest extends JUnit4CitrusTestDesigner {
private static final int PORT = 9123;
private static SocketServer socketServer;
private static Thread socketThread;
@BeforeClass
public static void setUp() throws Exception {
socketServer = new SocketServer(PORT);
socketThread = new Thread(socketServer);
socketThread.start();
}
@AfterClass
public static void tearDown() throws Exception {
socketServer.shutdown();
socketThread.join();
}
@Test
@CitrusTest(name = "sendSpringIntegrationMessageTest")
public void sendSpringIntegrationMessageTest() {
status(Status.DRAFT);
send("citrusServiceEndpoint").payload("Message 1");
send("citrusServiceEndpoint").payload("Message 2");
}
}
我希望这对可能遇到与我相同问题的任何人有所帮助。
您也可以为此使用 Citrus Apache Camel 集成。您需要 citrus-camel 模块和 camel-netty (http://camel.apache.org/netty.html) or camel-netty4 (http://camel.apache.org/netty4.html) 依赖项。那么就可以直接使用Camel Netty组件发送消息了:
@Test
@CitrusTest
public void sendNettyMessageTest() {
status(Status.DRAFT);
//sends data to server
send("camel:netty4:tcp://localhost:9123").payload("Message 1");
send("camel:netty4:tcp://localhost:9123").payload("Message 2");
}
这是在 Citrus 中使用动态端点,其中端点配置是在测试运行时创建的。所以这里几乎不需要额外的配置!
我想对使用 Netty 构建的套接字服务器进行一些单元测试。
Socket Server有如下简单代码:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class SocketServer implements Runnable {
private int port;
private EventLoopGroup bossGroup;
private EventLoopGroup workerGroup;
private ChannelFuture channelFuture;
private ServerBootstrap bootstrap;
public SocketServer(int port) {
this.port = port;
this.bossGroup = new NioEventLoopGroup();
this.workerGroup = new NioEventLoopGroup();
}
public int getPort() {
return port;
}
@Override
public void run() {
try {
bootstrap = new ServerBootstrap();
bootstrap
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline()
.addLast(new ReceiveMessageServerHandler())
.addLast(new ParseMessageServerHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
// Bind and start to accept incoming connections.
channelFuture = bootstrap.bind(port).sync();
// Wait until the server socket is closed
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
public void shutdown() throws InterruptedException {
channelFuture.channel().close();
}
}
在 MessageHandlers 上,我首先收到由“\n”分隔的短信。我非常需要一个 telnet 客户端。
我想测试我是否可以向服务器发送不同的消息,以及我是否会在一个时间范围内收到某些预期的响应。
我尝试使用 Citrus Framework,但我无法获得任何结果,因为它没有提供适当的纯文本协议(我尝试过 Rest、Soap 等,但它们对我没有好处)。我在 Citrus Reference 2.4 中找不到答案。
我在 post 问题之前解决了问题(我昨天写了问题,但直到今天我才 post ......我找到了答案) .
所以我终于可以用 Citrus Framework 和 Spring Integration 解决这个问题。
与同事一起阅读后,我能够使用 Spring 集成 TCP 适配器作为 Citrus 端点的通道(来自 java.nio 的 SocketChannel)。
Spring Integration Reference - IP
在这里你可能会看到我使用的citrus-context.xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:citrus="http://www.citrusframework.org/schema/config"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.citrusframework.org/schema/config http://www.citrusframework.org/schema/config/citrus-config.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/ip http://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd">
<citrus:channel-endpoint id="citrusServiceEndpoint"
channel-name="input" />
<int-ip:tcp-connection-factory id="client"
type="client" host="localhost" port="9123" single-use="true"
so-timeout="10000" using-nio="true" />
<int:channel id="input" />
<int-ip:tcp-outbound-channel-adapter
id="outboundClient" channel="input" connection-factory="client" />
</beans>
在我的 Citrus 测试中,我能够根据需要发送消息:
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.consol.citrus.TestCaseMetaInfo.Status;
import com.consol.citrus.annotations.CitrusTest;
import com.consol.citrus.dsl.junit.JUnit4CitrusTestDesigner;
public class MyFirstTest extends JUnit4CitrusTestDesigner {
private static final int PORT = 9123;
private static SocketServer socketServer;
private static Thread socketThread;
@BeforeClass
public static void setUp() throws Exception {
socketServer = new SocketServer(PORT);
socketThread = new Thread(socketServer);
socketThread.start();
}
@AfterClass
public static void tearDown() throws Exception {
socketServer.shutdown();
socketThread.join();
}
@Test
@CitrusTest(name = "sendSpringIntegrationMessageTest")
public void sendSpringIntegrationMessageTest() {
status(Status.DRAFT);
send("citrusServiceEndpoint").payload("Message 1");
send("citrusServiceEndpoint").payload("Message 2");
}
}
我希望这对可能遇到与我相同问题的任何人有所帮助。
您也可以为此使用 Citrus Apache Camel 集成。您需要 citrus-camel 模块和 camel-netty (http://camel.apache.org/netty.html) or camel-netty4 (http://camel.apache.org/netty4.html) 依赖项。那么就可以直接使用Camel Netty组件发送消息了:
@Test
@CitrusTest
public void sendNettyMessageTest() {
status(Status.DRAFT);
//sends data to server
send("camel:netty4:tcp://localhost:9123").payload("Message 1");
send("camel:netty4:tcp://localhost:9123").payload("Message 2");
}
这是在 Citrus 中使用动态端点,其中端点配置是在测试运行时创建的。所以这里几乎不需要额外的配置!