Java >> Java tutorial >  >> Tag >> HTTP

Sådan håner du HttpServletRequest

1. Oversigt

I denne hurtige vejledning vil vi se på nogle få måder at håne en HttpServletRequest objekt .

Først starter vi med en fuldt funktionel mock-type – MockHttpServletRequest fra Forårstestbiblioteket. Derefter vil vi se, hvordan man tester ved hjælp af to populære hånende biblioteker – Mockito og JMockit. Til sidst vil vi se, hvordan man tester ved hjælp af en anonym underklasse.

2. Test af HttpServletRequest

Det kan være vanskeligt at teste Servlets, når vi ønsker at håne klientanmodningsoplysninger såsom HttpServletRequest . Derudover definerer denne grænseflade forskellige metoder, og der er forskellige tilgange til at håne disse metoder.

Lad os se på målet UserServlet klasse, som vi vil teste:

public class UserServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String firstName = request.getParameter("firstName");
        String lastName = request.getParameter("lastName");

        response.getWriter().append("Full Name: " + firstName + " " + lastName);
    }
}

For at enhedsteste doGet() metode, bliver vi nødt til at håne begge anmodninger og svar parametre for at simulere den faktiske køretidsadfærd.

3. Brug af MockHttpServletRequest fra foråret

Spring-Test bibliotek giver en fuldt funktionel klasse MockHttpServletRequest der implementerer HttpServletRequest grænseflade.

Selvom dette bibliotek primært er rettet mod at teste Spring-applikationer, kan vi bruge dets MockHttpServletRequest klasse uden at implementere nogen Spring-specifik funktionalitet. Med andre ord, selvom applikationen ikke bruger Spring, kan vi stadig have denne afhængighed bare for at håne HttpServletRequest objekter.

Lad os tilføje denne afhængighed til pom.xml:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.3.20</version>
    <scope>test</scope>
</dependency>

Lad os nu se, hvordan vi kan bruge denne klasse til at teste UserServlet :

@Test
void givenHttpServletRequest_whenUsingMockHttpServletRequest_thenReturnsParameterValues() throws IOException {
    MockHttpServletRequest request = new MockHttpServletRequest();
    request.setParameter("firstName", "Spring");
    request.setParameter("lastName", "Test");
    MockHttpServletResponse response = new MockHttpServletResponse();

    servlet.doGet(request, response);

    assertThat(response.getContentAsString()).isEqualTo("Full Name: Spring Test");
}

Her kan vi bemærke, at der ikke er nogen egentlig hån involveret. Vi har brugt de fuldt funktionelle anmodnings- og svarobjekter og testet målklassen med blot nogle få linjer kode. Som et resultat er testkoden ren, læsbar og vedligeholdelsesfri.

4. Brug af Mocking Frameworks

Alternativt giver mocking frameworks en ren og enkel API til at teste mock-objekter, der efterligner det originale objekts køretidsadfærd .

Nogle af deres stærke sider er deres udtryksevne og den helt klare evne til at håne statisk og privat metoder. Yderligere kan vi undgå det meste af den standardkode, der er nødvendig for at håne (sammenlignet med brugerdefinerede implementeringer) og i stedet fokusere på testene.

4.1. Brug af Mockito

Mockito er en populær open source-testautomatiseringsramme, der internt bruger Java Reflection API til at skabe falske objekter.

Lad os komme i gang ved at tilføje mockito-kerne-afhængigheden til vores pom.xml :

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.4.0</version>
    <scope>test</scope>
</dependency>

Lad os derefter se, hvordan vi kan håne getParameter() metode fra HttpServletRequest objekt:

@Test
void givenHttpServletRequest_whenMockedWithMockito_thenReturnsParameterValues() throws IOException {
    // mock HttpServletRequest & HttpServletResponse
    HttpServletRequest request = mock(HttpServletRequest.class);
    HttpServletResponse response = mock(HttpServletResponse.class);

    // mock the returned value of request.getParameterMap()
    when(request.getParameter("firstName")).thenReturn("Mockito");
    when(request.getParameter("lastName")).thenReturn("Test");
    when(response.getWriter()).thenReturn(new PrintWriter(writer));

    servlet.doGet(request, response);

    assertThat(writer.toString()).isEqualTo("Full Name: Mockito Test");
}

4.2. Brug af JMockit

JMockit er en hånlig API, der giver nyttig optagelses- og verifikationssyntaks (vi kan bruge den til både JUnit og TestNG). Det er et integrationstestbibliotek uden for beholderen til Java EE og Spring-baserede apps. Lad os se, hvordan vi kan håne HttpServletRequest ved hjælp af JMockit.

Først tilføjer vi jmockit afhængighed af vores projekt:

<dependency> 
    <groupId>org.jmockit</groupId> 
    <artifactId>jmockit</artifactId> 
    <version>1.49</version>
    <scope>test</scope>
</dependency>

Lad os derefter fortsætte med den falske implementering i testklassen:

@Mocked
HttpServletRequest mockRequest;
@Mocked
HttpServletResponse mockResponse;

@Test
void givenHttpServletRequest_whenMockedWithJMockit_thenReturnsParameterValues() throws IOException {
    new Expectations() {{
        mockRequest.getParameter("firstName"); result = "JMockit";
        mockRequest.getParameter("lastName"); result = "Test";
        mockResponse.getWriter(); result = new PrintWriter(writer);
    }};

    servlet.doGet(mockRequest, mockResponse);

    assertThat(writer.toString()).isEqualTo("Full Name: JMockit Test");
}

Som vi kan se ovenfor, med blot et par linjers opsætning, har vi testet målklassen med succes med en mock HttpServletRequest objekt.

Således kan hånende rammer spare os for en masse benarbejde og gøre enhedstest meget hurtigere at skrive . Tværtimod, for at bruge mock-objekter, skal man forstå mock API, og normalt kræver det en separat ramme.

5. Brug af anonym underklasse

Nogle projekter kan have afhængighedsbegrænsninger eller foretrækker direkte kontrol over deres egne testklasseimplementeringer. Specifikt kan dette være nyttigt i tilfælde af en større servlet-kodebase, hvor genbrugbarheden af ​​tilpassede implementeringer er vigtig. I disse tilfælde er anonyme klasser nyttige.

Anonyme klasser er indre klasser uden navn . Desuden er de hurtige at implementere og giver direkte kontrol over det faktiske objekt. Denne tilgang kan overvejes, hvis vi ikke ønsker at inkludere en yderligere afhængighed til test.

Lad os nu oprette en anonym underklasse, der implementerer HttpServletRequest grænsefladen og brug den til at teste doGet() metode:

public static HttpServletRequest getRequest(Map<String, String[]> params) {
    return new HttpServletRequest() {
        public Map<String, String[]> getParameterMap() {
            return params;
        }

        public String getParameter(String name) {
            String[] values = params.get(name);
            if (values == null || values.length == 0) {
                return null;
            }
            return values[0];
        }

        // More methods to implement
    }
};

Lad os derefter videregive denne anmodning til klassen under test:

@Test
void givenHttpServletRequest_whenUsingAnonymousClass_thenReturnsParameterValues() throws IOException {
    final Map<String, String[]> params = new HashMap<>();
    params.put("firstName", new String[] { "Anonymous Class" });
    params.put("lastName", new String[] { "Test" });

    servlet.doGet(getRequest(params), getResponse(writer));

    assertThat(writer.toString()).isEqualTo("Full Name: Anonymous Class Test");
}

Ulempen ved denne løsning er behovet for at oprette en anonym klasse med dummy-implementeringer til alle abstrakte metoder. Desuden der er chancer for, at indlejrede objekter som HttpSession kan kræve specifikke implementeringer .

6. Konklusion

I denne artikel diskuterede vi et par muligheder for at håne HttpServletRequest objekt ved skrivning af enhedstest til servlets. Udover at bruge de hånlige rammer, så vi, at test med MockHttpServletRequest klasse ser ud til at være mere ren og effektiv end brugerdefinerede implementeringer.

Som altid er koden til disse eksempler tilgængelig på GitHub.


Java tag