使用 Spock 和 Java Spark 测试 QueryParams

Test QueryParams with Spock and Java Spark

我正在与 Java Spark 和 Groovy Spock 一起进行测试。我目前正在尝试从 URI 测试 queryParams,但我似乎无法弄明白。

实际上我有一些测试用于测试路径参数,如下所示:

import spark.Request
import spark.routematch.RouteMatch
import spock.lang.Shared
import spock.lang.Specification

class ChargeRouterValidatorSpec extends Specification {
    @Shared
    HttpServletRequest servletRequest = Mock(HttpServletRequest.class)
    @Shared
    Request request

    void "test"() {
        given:
        RouteMatch match = new RouteMatch(null, "/charges/:id", "/charges/1" , "text/html")
        request = new Request(match, servletRequest)

        when:
        def test = request.params("id")

        then:
        test == "1"
    }
}

Spark Request使用changeMatch方法,从'/'中的RouteMatch中拆分第一个URI字符串和第二个URI字符串,比较并获取与以':'开头的拆分部分位置匹配的参数

完美,测试结果为 1。

现在,当我尝试测试 queryParams

import spark.Request
import spark.routematch.RouteMatch
import spock.lang.Shared
import spock.lang.Specification

class ChargeRouterValidatorSpec extends Specification {
    @Shared
    HttpServletRequest servletRequest = Mock(HttpServletRequest.class)
    @Shared
    Request request

    void "test"() {
        given:
        RouteMatch match = new RouteMatch(null, "/charges/:id", "/charges/1?test=test" , "text/html")
        request = new Request(match, servletRequest)

        when:
        def test = request.queryParams("test")

        then:
        test == "test"
    }
}

测试始终为空。

我的问题是我应该如何正确测试 queryParams?

我想补充一点,当我 运行 在本地尝试时,queryParams 可以正确评估,但我无法根据服务器进行测试。

我找到了解决办法。 Spock 具有与 Mockito when().thenReturn() 类似的功能,即 mock.method(param) >> wantedResult

所以测试看起来像这样:

import spark.Request
import spark.routematch.RouteMatch
import spock.lang.Shared
import spock.lang.Specification

class ChargeRouterValidatorSpec extends Specification {
@Shared
HttpServletRequest servletRequest = Mock(HttpServletRequest.class)
@Shared
Request request

void "test"() {
    given:
    RouteMatch match = new RouteMatch(null, "/charges/:id", "/charges/1" , "text/html")
    request = new Request(match, servletRequest)

    when:
    servletRequest.getParameter("test") >> "test"
    def test = request.queryParams("test")

    then:
    test == "test"
}
}

这评估正确。

我维持对你的测试的批评。这是没有意义的,因为您只是在测试该方法 Request.queryParams(String) returns 您定义为由模拟或存根 return 编辑的值。此外,您使用受包保护的构造函数创建 Request,这仅在您使用 Groovy 时有效。这是被测 class 的相关部分:

package spark;

// (...)

public class Request {

  // (...)

  private HttpServletRequest servletRequest;

  // (...)

  Request(RouteMatch match, HttpServletRequest request) {
    this.servletRequest = request;
    changeMatch(match);
  }

  public String queryParams(String queryParam) {
    return servletRequest.getParameter(queryParam);
  }

  // (...)
}

看到了吗?您只是在测试模拟可以 return 模拟结果。为什么要对第三方进行单元测试 class?这毫无意义,除非您的示例代码不是您的真实测试,而只是更大测试的一小部分,并且您实际上正在测试其他东西(您自己的 classes 之一)并且只需要模拟结果别的东西。但正如给出的那样,测试只是废话。

无论如何,关于它的价值,关于你的测试结构的一些提示:

  • 为什么要用@Shared? Spock 的美妙之处在于默认情况下不共享实例变量,以避免测试之间的副作用和依赖性。更糟糕的是,除非您完全删除 @Shared,否则您自己接受的解决方案中的代码会失败。我试过。你应该更加谨慎地发布你自己的问题的答案,这些问题甚至不起作用,然后甚至接受它们。

  • 您有两个测试用例,但只发布了其中一个的答案,甚至没有发布您之前遇到问题的那个。

  • 这两个测试用例在结构上也非常相似,唯一不同的是RouteMatch的请求URI。对于这种情况,我建议您使用 where:@Unroll 的参数化测试。它摆脱了重复的代码,并为测试和变量名称进行了一些重命名,使其更具可读性。

package de.scrum_master.Whosebug

import spark.Request
import spark.routematch.RouteMatch
import spock.lang.Specification
import spock.lang.Unroll
import javax.servlet.http.HttpServletRequest

class SparkJavaTest extends Specification {
  @Unroll
  def "Request returns expected value for query parameter '#requestUri'"() {
    given:
    def routeMatch = new RouteMatch(null, "/charges/:id", requestUri, "text/html")
    def servletRequest = Stub(HttpServletRequest) {
      getParameter("test") >> "test"
    }
    def request = new Request(routeMatch, servletRequest)

    expect:
    request.queryParams("test") == "test"

    where:
    requestUri << ["/charges/1", "/charges/1?test=test"]
  }
}

顺便说一句,您在上面的示例中使用 Mock() 还是 Stub() 取决于您。