java - 使用 Java 对客户端-服务器应用程序进行单元测试

标签 java multithreading sockets junit

我正在开发一个简单的客户端-服务器应用程序,我应该在单独的线程中初始化客户端和服务器对象。服务器包含我大学某些特定部门的所有类(class)的数据库,并且 GET 请求获取所请求部门的所有类(class)并将其发送回客户端。虽然我能够在主要方法中完美地测试所有内容,但单元测试不起作用。以下是我的单元测试代码:

import client.Client;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import server.Server;


public class ClientServerTest {
    private static String file = "";

    @BeforeClass
    public static void setFile(){
        file = System.getProperty("file");
    }

    @Before
    public void startServerTest(){
        Thread serverThread = new Thread(() -> {
            new Server(file);
        });
        serverThread.start();
    }

   @Test
   public void getTest(){
        Client client = new Client();
        Assert.assertTrue(client.submitRequest("GET COM"));
        Assert.assertTrue(client.submitRequest("GET MAT"));
        Assert.assertTrue(client.submitRequest("GET BIO"))
    }
}

当我运行测试时,服务器测试通过,我得到 getTest() 测试的以下输出:

java.net.ConnectException: Connection refused: connect

我一直在寻找让单元测试与线程一起工作的最佳方法,但我似乎无法弄清楚。任何帮助将不胜感激。

最佳答案

首先,正如我的同事所说,这与单元测试相去甚远,而是集成或端到端测试。

您的测试问题可能是某些线程的性能优于其他创建随机失败测试的线程,因此您需要一些选项来同步它们。

我可以说,使用 JUnit 进行此类测试是绝对可能的,但是需要将一些关键概念付诸实践才能进行此类测试,包括多线程、可重现(不是片状)以及任何有用的概念。

如果没有看到 Server 类的实现,这是相当困难的,但我尝试总结希望能让您走上正轨的提示。

第一:

在同一线程内(最好在主线程中)创建您的 Server 类和所有其他依赖项。

public static void main(String[] args) {
   Foo otherInstance = new Foo(...);
   Bar anotherInstance = new BarImpl(otherInstance,...);
   Server server = new Server(otherInstance, anotherInstance);
   server.start(); // blocking until app is stopped in a graceful way and where real application logic starts
   // not more to do here
}

重要的是,除了分配诸如 this.someVar = someVar 这样的实例变量之外,构造函数不能做任何“工作”。其背后的概念称为 dependency injection并使您的生活变得更加轻松,特别是如果您使用图书馆。

第二:

您的应用程序需要钩子(Hook),测试可以插入该钩子(Hook)来拦截您的逻辑,您可以在其中使线程停止并等待发生使测试工作所需的其他事件。插入何处很大程度上取决于您的应用程序。最有可能需要为测试中的某些类指定不同的实现,从而以不同的方式连接应用程序的依赖关系图。

要实现这一点,需要像CountDownLatch这样的同步辅助工具。是你在测试类里最好的 friend 。

@Test
public void someTest() {
    // or move the instantiation logic to the @Before setup method
    final CountDownLatch isConnected = new CountDownLatch(1);
    Foo otherInstance = new Foo(...);
    Bar anotherInstance = new BarTestImpl(otherInstance,...);
    // here we plug into the connected event
    anotherInstance.setConnectionListener(() -> { isConnected.countDown(); }
    Server server = new Server(otherInstance, anotherInstance);
    server.startAsync(); // not blocking
    ...
    // test logic starting, do some assertions or other stuff
    ...
    // block until connected event is received
    isConnected.await(1, TimeUnit.SECONDS);
    // do some assertions
    assertTrue(server.isConnected());
    ...
}

这个例子只是触及了可能性的表面,以及如何利用这个概念来维持高水平的自动化测试,但它应该展示背后的想法。

关于java - 使用 Java 对客户端-服务器应用程序进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46521297/

相关文章:

java - 旋转开关 View 的剪辑

multithreading - 如何进行 Mutlithreded idhttp 调用以在 StringList 上工作

java - AtomicBoolean 是否保证 "safe-thread"?

c# - 套接字编程的替代方案是什么?

c - Unix网络编程,协议(protocol)不支持的地址族

c - 从套接字读取

java - IntelliJ - 构建工件时访问被拒绝

java - PKIX 路径验证失败 : java. security.cert.CertPathValidatorException: signature check failed exception while connecting memsql ssl db

java - 为什么从浏览器下载的文件已损坏?

c++ - 在 Visual Studio 中直接调用 MATLAB(多线程)