web-dev-qa-db-fra.com

Comment créer un objet CloseableHttpResponse pour faciliter les tests?

J'essaie de construire un objet CloseableHttpResponse mock à renvoyer dans l'un de mes tests unitaires, mais il n'y a pas de constructeur pour cela. J'ai trouvé ceci DefaultHttpResponseFactory , mais cela ne fait qu'un HttpResponse. Qu'est-ce qu'un moyen simple de construire une CloseableHttpResponse? Dois-je appeler execute() dans mon test puis définir les statusLine et entity? Cela semble être une approche étrange.

Voici la méthode que j'essaie de me moquer:

public static CloseableHttpResponse getViaProxy(String url, String ip, int port, String username,
                                                String password) {
    CredentialsProvider credsProvider = new BasicCredentialsProvider();
    credsProvider.setCredentials(
            new AuthScope(ip, port),
            new UsernamePasswordCredentials(username, password));
    CloseableHttpClient httpclient = HttpClients.custom()
            .setDefaultCredentialsProvider(credsProvider).build();
    try {
        RequestConfig config = RequestConfig.custom()
                .setProxy(new HttpHost(ip, port))
                .build();
        HttpGet httpGet = new HttpGet(url);
        httpGet.setConfig(config);

        LOGGER.info("executing request: " + httpGet.getRequestLine() + " via proxy ip: " + ip + " port: " + port +
                " username: " + username + " password: " + password);

        CloseableHttpResponse response = null;
        try {
            return httpclient.execute(httpGet);
        } catch (Exception e) {
            throw new RuntimeException("Could not GET with " + url + " via proxy ip: " + ip + " port: " + port +
                    " username: " + username + " password: " + password, e);
        } finally {
            try {
                response.close();
            } catch (Exception e) {
                throw new RuntimeException("Could not close response", e);
            }
        }
    } finally {
        try {
            httpclient.close();
        } catch (Exception e) {
            throw new RuntimeException("Could not close httpclient", e);
        }
    }
}

Voici le code factice utilisant PowerMockito:

    mockStatic(HttpUtils.class);
    when(HttpUtils.getViaProxy("http://www.google.com", anyString(), anyInt(), anyString(), anyString()).thenReturn(/*mockedCloseableHttpResponseObject goes here*/)
15
Popcorn

Suivez ces étapes peuvent aider:

1.mock it (ex. Mockito)

CloseableHttpResponse response = mock(CloseableHttpResponse.class);
HttpEntity entity = mock(HttpEntity.class);

2.appliquer des règles

when(response.getStatusLine()).thenReturn(new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "FINE!"));
when(entity.getContent()).thenReturn(getClass().getClassLoader().getResourceAsStream("result.txt"));
when(response.getEntity()).thenReturn(entity);

3. l'utiliser 

when(httpClient.execute((HttpGet) any())).thenReturn(response);
22
nnguyen07

Cela fait un moment que cette question a été posée, mais je veux fournir une solution que j'ai utilisée.

J'ai créé une petite classe qui étend la classe BasicHttpResponse et implémente l'interface CloseableHttpResponse (qui n'a rien d'autre qu'une méthode pour fermer la réponse). Étant donné que la classe BasicHttpResponse contient des méthodes de définition pour à peu près tout, je peux définir tous les champs nécessaires avec le code suivant:

public static CloseableHttpResponse buildMockResponse() throws FileNotFoundException {
    ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
    String reasonPhrase = "OK";
    StatusLine statusline = new BasicStatusLine(protocolVersion, HttpStatus.SC_OK, reasonPhrase);
    MockCloseableHttpResponse mockResponse = new MockCloseableHttpResponse(statusline);
    BasicHttpEntity entity = new BasicHttpEntity();
    URL url = Thread.currentThread().getContextClassLoader().getResource("response.txt");
    InputStream instream = new FileInputStream(new File(url.getPath()));
    entity.setContent(instream);
    mockResponse.setEntity(entity);
    return mockResponse;
}

Je règle essentiellement tous les champs, qui sont utilisés par le code réel. Cela inclut également la lecture d'un contenu de réponse fictive à partir d'un fichier dans un flux.

1
superM

Je souhaitais également créer une réponse concrète CloseableHttpResponse plutôt qu'une réplique. Je l'ai donc repérée dans le code source du client HTTP Apache.

Dans MainClientExec , toutes les valeurs renvoyées par execute ressemblent à:

return new HttpResponseProxy(response, connHolder);

où connHolder peut être null.

HttpResponseProxy est juste un wrapper fin qui effectue une fermeture sur le connHolder. Malheureusement, il est protégé par un package, il n'est donc pas (nécessairement) visible.

Ce que j'ai fait était de créer un "PublicHttpResponseProxy"

package org.Apache.http.impl.execchain;

import org.Apache.http.HttpResponse;

public class PublicHttpResponseProxy extends HttpResponseProxy {

    public PublicHttpResponseProxy(HttpResponse original) {
        super(original, null);
    }
}

Doit être dans le package "org.Apache.http.impl.execchain" (!) Déforme essentiellement la visibilité en public et fournit un constructeur avec un gestionnaire de connexion nul.

Maintenant, je peux instancier une concrète CloseableHttpResponse avec

CloseableHttpResponse response = new PublicHttpResponseProxy(basicResponse);

Les mises en garde habituelles s'appliquent. Étant donné que le proxy est protégé par un package, il ne fait pas partie de l'API officielle. Vous pouvez donc lancer le dé pour indiquer qu'il ne sera plus disponible par la suite. D'autre part, il n'y a pas grand chose à faire, vous pouvez donc facilement en écrire votre propre version. Il y aurait du couper-coller, mais ce ne serait pas si grave.

1
Rob

nvm, j’ai fini par le pirater en utilisant execute():

private CloseableHttpResponse getMockClosesableHttpResponse(HttpResponse response) throws Exception {
    CloseableHttpClient httpClient = HttpClients.createDefault();
    CloseableHttpResponse closeableHttpResponse = httpClient.execute(new HttpGet("http://www.test.com"));
    closeableHttpResponse.setEntity(response.getEntity());
    closeableHttpResponse.setStatusLine(response.getStatusLine());
    return closeableHttpResponse;
}
0
Popcorn