简体   繁体   中英

Test QueryParams with Spock and Java Spark

I am working with Java Spark and Groovy Spock for testing. I am currently trying to test queryParams from an URI but i can't seem to figure it out.

Actually i have a few tests working for testing path params like this:

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 uses changeMatch method which splits the first URI string from RouteMatch in '/' as well as the second URI string, compares and gets params which match the position of split parts that begin with ':'

That works perfect and test evaluates to 1.

Now, when i try to test 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"
    }
}

Test is always null.

My question is how should i correctly test for queryParams?

I want to add that when i run locally and try it, queryParams evaluates correctly but i can't make tests depending on a server.

I have found a solution. Spock has a similar function to Mockito when().thenReturn() which is mock.method(param) >> wantedResult

So the test looks like this:

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"
}
}

This evaluates correctly.

I sustain my criticism of your test. It is meaningless because you are just testing that method Request.queryParams(String) returns the value you define to be returned by your mock or stub. Furthermore, you create the Request using a package-protected constructor, which only works because you are using Groovy. Here is the relevant part of the class under test:

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);
  }

  // (...)
}

See? You are just testing that the mock can return a mock result. And why are you unit-testing a third-party class anyway? This makes no sense whatsoever, unless your sample code is not your real test but just s small part of a bigger test and you are actually testing something else (one of your own classes) and just need the mock result for something else. But as given, the test is just nonsense.

Anyway, for what it is worth, a few hints about your test structure:

  • Why use @Shared ? The beauty of Spock is that instance variables are not shared by default so as to avoid side effects and dependencies between tests. Even worse, the code in your own, accepted solution fails unless you remove @Shared altogether. I tried. You should be more cautious about posting answers to your own questions which do not even work and then even accepting them.

  • You have two test cases, but only posted an answer for one of them, but not even the one you had problems with before.

  • The two test cases are also very similar in structure, the only thing which is different is the request URI for the RouteMatch . I suggest you use a parametrised test with where: and @Unroll for this case. It gets rid of duplicate code and with a few renames for the test and variable names is more readable.

package de.scrum_master.stackoverflow

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"]
  }
}

BTW, whether you use Mock() or Stub() in the example above, is up to you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM