web-dev-qa-db-fra.com

Tests unitaires avec Android volley

J'aimerais savoir comment créer des tests unitaires pour le cadre de volley. Simulez les requêtes, les réponses afin que je puisse créer des tests unitaires ne nécessitant pas de service Web ni d'accès réseau.

Je l'ai googlé mais je ne trouve pas beaucoup d'informations sur le framework

37
apinho

J'ai implémenté une sous-classe de HttpStack named FakeHttpStack qui charge le faux corps de réponse à partir d'un fichier local situé dans le répertoire res/raw. J’ai fait cela à des fins de développement, c’est-à-dire que je peux développer quelque chose pour une nouvelle API avant que le serveur ne soit prêt, mais vous pouvez apprendre quelque chose (par exemple, remplacer HttpStack # peformRequest et createEntity) à partir de cet emplacement.

/**
 * Fake {@link HttpStack} that returns the fake content using resource file in res/raw.
 */
class FakeHttpStack implements HttpStack {
    private static final String DEFAULT_STRING_RESPONSE = "Hello";
    private static final String DEFAULT_JSON_RESPONSE = " {\"a\":1,\"b\":2,\"c\":3}";
    private static final String URL_PREFIX = "http://example.com/";
    private static final String LOGGER_TAG = "STACK_OVER_FLOW";

    private static final int SIMULATED_DELAY_MS = 500;
    private final Context context;

    FakeHttpStack(Context context) {
        this.context = context;
    }

    @Override
    public HttpResponse performRequest(Request<?> request, Map<String, String> stringStringMap)
            throws IOException, AuthFailureError {
        try {
            Thread.sleep(SIMULATED_DELAY_MS);
        } catch (InterruptedException e) {
        }
        HttpResponse response
                = new BasicHttpResponse(new BasicStatusLine(HttpVersion.HTTP_1_1, 200, "OK"));
        List<Header> headers = defaultHeaders();
        response.setHeaders(headers.toArray(new Header[0]));
        response.setLocale(Locale.JAPAN);
        response.setEntity(createEntity(request));
        return response;
    }

    private List<Header> defaultHeaders() {
        DateFormat dateFormat = new SimpleDateFormat("EEE, dd mmm yyyy HH:mm:ss zzz");
        return Lists.<Header>newArrayList(
                new BasicHeader("Date", dateFormat.format(new Date())),
                new BasicHeader("Server",
                        /* Data below is header info of my server */
                        "Apache/1.3.42 (Unix) mod_ssl/2.8.31 OpenSSL/0.9.8e")
        );
    }

    /**
     * returns the fake content using resource file in res/raw. fake_res_foo.txt is used for
     * request to http://example.com/foo
     */
    private HttpEntity createEntity(Request request) throws UnsupportedEncodingException {
        String resourceName = constructFakeResponseFileName(request);
        int resourceId = context.getResources().getIdentifier(
                resourceName, "raw", context.getApplicationContext().getPackageName());
        if (resourceId == 0) {
            Log.w(LOGGER_TAG, "No fake file named " + resourceName
                    + " found. default fake response should be used.");
        } else {
            InputStream stream = context.getResources().openRawResource(resourceId);
            try {
                String string = CharStreams.toString(new InputStreamReader(stream, Charsets.UTF_8));
                return new StringEntity(string);
            } catch (IOException e) {
                Log.e(LOGGER_TAG, "error reading " + resourceName, e);
            }
        }

        // Return default value since no fake file exists for given URL.
        if (request instanceof StringRequest) {
            return new StringEntity(DEFAULT_STRING_RESPONSE);
        }
        return new StringEntity(DEFAULT_JSON_RESPONSE);
    }

    /**
     * Map request URL to fake file name
     */
    private String constructFakeResponseFileName(Request request) {
        String reqUrl = request.getUrl();
        String apiName = reqUrl.substring(URL_PREFIX.length());
        return "fake_res_" + apiName;
    }
}

Pour utiliser FakeHttpStack, il vous suffit de le transmettre à votre RequestQueue . Je remplace aussi RequestQueue.

public class FakeRequestQueue extends RequestQueue {
    public FakeRequestQueue(Context context) {
        super(new NoCache(), new BasicNetwork(new FakeHttpStack(context)));
    }
}

Le point positif de cette approche est qu’il n’exige pas beaucoup de changement dans votre code. Vous devez simplement changer votre RequestQueue en FakeRequestQueue lors du test. Ainsi, il peut être utilisé dans des tests d'acceptation ou des tests de système.

D'autre part, pour les tests unitaires, il pourrait y avoir une manière plus compacte. Par exemple, vous pouvez implémenter votre Request.Listener sous-classe en tant que classe distincte afin que la méthode onResponse puisse être facilement testée. Je vous recommande de mettre plus de détails sur ce que vous voulez tester ou de mettre un fragment de code.

22
Kazuki

Jetez un oeil à volley tests folder, où vous pouvez trouver des exemples.

MockCache.Java
MockHttpClient.Java
MockHttpStack.Java
MockHttpURLConnection.Java
MockNetwork.Java
MockRequest.Java
MockResponseDelivery.Java
8
Dmytro Danylyk

Je ne suis pas sûr à 100% que je comprends ce que vous voulez faire, mais si je le fais, alors easymock (une bibliothèque qui permet de créer des classes factices, de pouvoir appeler et recevoir des réponses prédéterminées) vous aidera beaucoup. Un gars du nom de Lars Vogel a publié un article intéressant sur ce sujet que j’ai trouvé utile il ya quelque temps quand je l’utilisais.

http://www.vogella.com/articles/EasyMock/article.html

0
erbsman

Voici une copie de le MockHttpStack de volley actuel mentionné par @Dmytro

package com.Android.volley.mock;
import com.Android.volley.AuthFailureError;
import com.Android.volley.Request;
import com.Android.volley.toolbox.HttpStack;
import org.Apache.http.HttpResponse;
import Java.io.IOException;
import Java.util.HashMap;
import Java.util.Map;
public class MockHttpStack implements HttpStack {
    private HttpResponse mResponseToReturn;
    private IOException mExceptionToThrow;
    private String mLastUrl;
    private Map<String, String> mLastHeaders;
    private byte[] mLastPostBody;
    public String getLastUrl() {
        return mLastUrl;
    }
    public Map<String, String> getLastHeaders() {
        return mLastHeaders;
    }
    public byte[] getLastPostBody() {
        return mLastPostBody;
    }
    public void setResponseToReturn(HttpResponse response) {
        mResponseToReturn = response;
    }
    public void setExceptionToThrow(IOException exception) {
        mExceptionToThrow = exception;
    }
    @Override
    public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
            throws IOException, AuthFailureError {
        if (mExceptionToThrow != null) {
            throw mExceptionToThrow;
        }
        mLastUrl = request.getUrl();
        mLastHeaders = new HashMap<String, String>();
        if (request.getHeaders() != null) {
            mLastHeaders.putAll(request.getHeaders());
        }
        if (additionalHeaders != null) {
            mLastHeaders.putAll(additionalHeaders);
        }
        try {
            mLastPostBody = request.getBody();
        } catch (AuthFailureError e) {
            mLastPostBody = null;
        }
        return mResponseToReturn;
    }
}
0
serv-inc