83

I have a service that does some work on an HttpServletRequest object, specifically using the request.getParameterMap and request.getParameter to construct an object.

I was wondering if there is a straightforward way to take a provided url, in the form of a string, say

String url = "http://www.example.com/?param1=value1&param";

and easily convert it to a HttpServletRequest object so that I can test it with my unit tests? Or at least just so that request.getParameterMap and request.getParameter work correctly?

Anthony
  • 855
  • 1
  • 6
  • 6

5 Answers5

66

Here it is how to use MockHttpServletRequest:

// given
MockHttpServletRequest request = new MockHttpServletRequest();
request.setServerName("www.example.com");
request.setRequestURI("/foo");
request.setQueryString("param1=value1&param");

// when
String url = request.getRequestURL() + '?' + request.getQueryString(); // assuming there is always queryString.

// then
assertThat(url, is("http://www.example.com:80/foo?param1=value1&param"));
Guito
  • 1,181
  • 1
  • 9
  • 19
  • 1
    Using this MockHttpServletRequest actually does the job as I just needed a fully functional HttpServletRequest – Duc Tran Apr 08 '15 at 17:59
  • 3
    Note that when setting the queryString the parameter Map is not updated automatically in MockHttpServletRequest. So if you use request.getParameter() in your code, you'll have to explicitly set it first the test setup even though it might seem redundant at first. – Nicola Ambrosetti Nov 24 '16 at 08:48
  • I noticed the same. Query-string and Parameters does not seem to sync up – Raj Sep 20 '19 at 04:03
  • jee api jar 6 or 8 will be needed for this. – Smart Coder Jul 01 '20 at 18:07
  • Outdated https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/mock/web/MockHttpServletRequest.html – Simplicity's_Strength Sep 13 '21 at 16:51
53

Spring has MockHttpServletRequest in its spring-test module.

If you are using maven you may need to add the appropriate dependency to your pom.xml. You can find spring-test at mvnrepository.com.

B--rian
  • 5,578
  • 10
  • 38
  • 89
pap
  • 27,064
  • 6
  • 41
  • 46
40

Simplest ways to mock an HttpServletRequest:

  1. Create an anonymous subclass:

    HttpServletRequest mock = new HttpServletRequest ()
    {
        private final Map<String, String[]> params = /* whatever */
    
        public Map<String, String[]> getParameterMap()
        {
            return params;
        }
    
        public String getParameter(String name)
        {
            String[] matches = params.get(name);
            if (matches == null || matches.length == 0) return null;
            return matches[0];
        }
    
        // TODO *many* methods to implement here
    };
    
  2. Use jMock, Mockito, or some other general-purpose mocking framework:

    HttpServletRequest mock = context.mock(HttpServletRequest.class); // jMock
    HttpServletRequest mock2 = Mockito.mock(HttpServletRequest.class); // Mockito
    
  3. Use HttpUnit's ServletUnit and don't mock the request at all.

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
4

You would generally test these sorts of things in an integration test, which actually connects to a service. To do a unit test, you should test the objects used by your servlet's doGet/doPost methods.

In general you don't want to have much code in your servlet methods, you would want to create a bean class to handle operations and pass your own objects to it and not servlet API objects.

Rocky Pulley
  • 22,531
  • 20
  • 68
  • 106
  • 1
    Then again, why would you pass the opportunity to increase your test coverage (i.e. your code robustness) just because the method happen to take a certain type of parameter as input? – pap Jun 23 '11 at 14:17
  • 1
    It depends, are you trying to unit test the servlet API or are you trying to unit test your own code? – Rocky Pulley Jun 23 '11 at 14:19
  • 5
    "In general" you don't want to have any code in your servlet methods. In practice, you always will. And you will have helper-classes, utility methods, parsing, validations, model translations and sometimes even business-logic (the horror!). And since you do, you will want to unit-test them. And because of that, you'll want to mock servlet requests to create well-defined test scenarios. Mocking the servlet API is precisely the OPPOSITE of testing it. It's removing it from the test case entirely. – pap Jun 23 '11 at 14:47
2

for those looking for a way to mock POST HttpServletRequest with Json payload, the below is in Kotlin, but the key take away here is the DelegatingServetInputStream when you want to mock the request.getInputStream from the HttpServletRequest

@Mock
private lateinit var request: HttpServletRequest

@Mock
private lateinit var response: HttpServletResponse

@Mock
private lateinit var chain: FilterChain

@InjectMocks
private lateinit var filter: ValidationFilter


@Test
fun `continue filter chain with valid json payload`() {
    val payload = """{
      "firstName":"aB",
      "middleName":"asdadsa",
      "lastName":"asdsada",
      "dob":null,
      "gender":"male"
    }""".trimMargin()

    whenever(request.requestURL).
        thenReturn(StringBuffer("/profile/personal-details"))
    whenever(request.method).
        thenReturn("PUT")
    whenever(request.inputStream).
        thenReturn(DelegatingServletInputStream(ByteArrayInputStream(payload.toByteArray())))

    filter.doFilter(request, response, chain)

    verify(chain).doFilter(request, response)
}
mel3kings
  • 8,857
  • 3
  • 60
  • 68