7

我正在使用Spark Web 框架并创建一个RESTful API。(http://sparkjava.com,因为那里有多个名为“Spark”的东西)

我的雇主的标准要求我们编写一系列单元测试,这些单元测试将每天自动运行一次,以确认应用程序仍在运行。

Spark 很容易使用 Postman 之类的工具来测试自己,但我还没有找到任何JUnit使用 Spark 编写测试的好例子,甚至没有发现使用它以编程方式发出HTTP 请求的任何好例子。

有没有人这样做过?可能吗?

4

4 回答 4

9

我们开发了一个小型库,可以方便地对 Spark 控制器/端点进行单元测试。

Github

此外,1.1.3 版发布在 Maven 中央存储库中

<dependency>
        <groupId>com.despegar</groupId>
        <artifactId>spark-test</artifactId>
        <version>1.1.3</version>
        <scope>test</scope>
    </dependency>
于 2016-02-04T12:46:14.223 回答
5

我有同样的要求,你和我找到了一种让它工作的方法。我搜索了 Spark 源代码,发现了两个有用的类:

  • SparkTestUtil:此类包装 Apache HttpClient 并公开方法以针对具有可自定义端口(在构造函数中)和相对路径(在请求方法中)的本地 Web 服务器(在 localhost 中运行)发出不同的 http 请求
  • ServletTest:它在本地端口中启动一个 Jetty 实例,其中包含应用程序上下文和可以找到 WEB-INF/web.xml 文件描述符的相对目录路径。此 web.xml 将用于模拟 Web 应用程序。然后它使用SparkTestUtil对这个模拟的应用程序发出 http 请求并断言结果。

这就是我所做的:我创建了一个实现SparkApplication接口的 junit 测试类。在该接口中,我创建并初始化负责回答 http 请求的“控制器”(我的应用程序的一个类)。在使用 @BeforeClass 注释的方法中,我使用 web.xml 初始化 Jetty 实例,该 web.xml 将 junit 测试类称为 SparkApplication 和SparkTestUtil

JUnit 测试类

package com.test

import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.webapp.WebAppContext;

public class ControllerTest implements SparkApplication {

    private static SparkTestUtil sparkTestUtil;

    private static Server webServer;

    @Override
    public void init() {
         new Controller(...)
    }

    @BeforeClass
    public static void beforeClass() throws Exception {
       sparkTestUtil = new SparkTestUtil(PORT);
       webServer = new Server();
       ServerConnector connector = new ServerConnector(webServer);
       connector.setPort(PORT);
       webServer.setConnectors(new Connector[] {connector});
       WebAppContext bb = new WebAppContext();
       bb.setServer(webServer);
       bb.setContextPath("/");
       bb.setWar("src/test/webapp/");
       webServer.setHandler(bb);
       webServer.start();
       (...)
    }

    @AfterClass
    public static void afterClass() throws Exception {
       webServer.stop();
       (...)
    }    

}

src/test/webapp/WEB-INF/web.xml 文件

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>
    <filter>
        <filter-name>SparkFilter</filter-name>
        <filter-class>spark.servlet.SparkFilter</filter-class>
        <init-param>
            <param-name>applicationClass</param-name>
            <param-value>com.test.ControllerTest</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>SparkFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

这可以改进,但我认为这是一个很好的起点。也许可以创建一些“火花测试”组件?

希望这对你有用!

于 2016-01-19T14:51:17.077 回答
1

这是我的解决方案。您只需要额外添加 apache-http 和 junit 依赖项。

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.2</version>
</dependency>

public class SparkServer {
    public static void main(String[] args) {
        Spark.port(8888);
        Spark.threadPool(1000, 1000,60000);
        Spark.get("/ping", (req, res) -> "pong");
    }
}

public class SparkTest {
    @Before
    public void setup() {
        SparkServer.main(null);
    }
    @After
    public void tearDown() throws Exception {
        Thread.sleep(1000);
        Spark.stop();
    }
    @Test
    public void test() throws IOException {

        CloseableHttpClient httpClient = HttpClients.custom()
                .build();

        HttpGet httpGet = new HttpGet("http://localhost:8888/ping");
        CloseableHttpResponse response = httpClient.execute(httpGet);

        int statusCode = response.getStatusLine().getStatusCode();
        BufferedReader rd = new BufferedReader(
                 new InputStreamReader(response.getEntity().getContent()));

        StringBuffer result = new StringBuffer();
        String line = "";
        while ((line = rd.readLine()) != null) {
            result.append(line);
        }

        assertEquals(200, statusCode);
        assertEquals("pong", result.toString());
    }
}
于 2017-03-14T02:07:21.527 回答
0

另一种方法是创建一个在每个path或中实现 Route 的类route。例如,如果您有如下路线:

get("maintenance/task", (req, response) -> {....}); 

然后将(req, response) -> {....}lambda 替换为实现Route.

例如:

public class YourRoute implements Route {
   public Object handle(Request request, Response response) throws Exception {
     ....
   }
}

将会:

get("maintenance/task", new YourRoute()); 

然后您可以YourRoute使用 JUnit 对类进行单元测试。


于 2017-10-05T07:46:01.423 回答