2012-04-13 4 views
5

Ho una classe:Come testare una classe che usa HttpClient in Android usando il framework integrato?

public class WebReader implements IWebReader { 

    HttpClient client; 

    public WebReader() { 
     client = new DefaultHttpClient(); 
    } 

    public WebReader(HttpClient httpClient) { 
     client = httpClient; 
    } 

    /** 
    * Reads the web resource at the specified path with the params given. 
    * @param path Path of the resource to be read. 
    * @param params Parameters needed to be transferred to the server using POST method. 
    * @param compression If it's needed to use compression. Default is <b>true</b>. 
    * @return <p>Returns the string got from the server. If there was an error downloading file, 
    * an empty string is returned, the information about the error is written to the log file.</p> 
    */ 
    public String readWebResource(String path, ArrayList<BasicNameValuePair> params, Boolean compression) { 
      HttpPost httpPost = new HttpPost(path); 
      String result = ""; 

      if (compression) 
       httpPost.addHeader("Accept-Encoding", "gzip"); 
      if (params.size() > 0){ 
       try { 
        httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); 
       } catch (UnsupportedEncodingException e1) { 
        e1.printStackTrace(); 
       } 
      } 

      try { 
       HttpResponse response = client.execute(httpPost); 
       StatusLine statusLine = response.getStatusLine(); 
       int statusCode = statusLine.getStatusCode(); 
       if (statusCode == 200) { 
        HttpEntity entity = response.getEntity(); 
        InputStream content = entity.getContent(); 
        if (entity.getContentEncoding() != null 
          && "gzip".equalsIgnoreCase(entity.getContentEncoding() 
            .getValue())) 
         result = uncompressInputStream(content); 
        else 
         result = convertStreamToString(content); 
       } else { 
        Log.e(MyApp.class.toString(), "Failed to download file"); 
       } 
      } catch (ClientProtocolException e) { 
       e.printStackTrace(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 

      return result; 
     } 

    private String uncompressInputStream(InputStream inputStream) 
      throws IOException {...} 

    private String convertStreamToString(InputStream is) {...} 

} 

non riesco a trovare un modo per testare utilizzando un framework standard. Soprattutto, ho bisogno di simulare la perdita totale di Internet dall'interno del test.

ci sono suggerimenti per trasformare manualmente Internet nell'emulatore fuori durante l'esecuzione del test. Ma non mi sembra una buona soluzione, perché i test automatici dovrebbero essere ... automatici.

ho aggiunto un campo "client" per la classe cercando di prendere in giro dall'interno della classe di test. Ma l'implementazione dell'interfaccia HttpClient sembra abbastanza complessa.

Il framework Robolectric consente agli sviluppatori di testare Http connection per quanto ne so. Ma immagino che ci sia un modo per scrivere un test del genere senza usare un framework aggiuntivo così grande.

Quindi ci sono modi brevi e semplici delle classi di unit test che utilizzano HttpClient? Come hai risolto questo nei tuoi progetti?

risposta

6

Ho aggiunto un campo "client" alla classe cercando di deriderlo dall'interno della classe di test. Ma l'implementazione dell'interfaccia HttpClient sembra abbastanza complessa.

Sono un po 'confuso su questa affermazione. Dal titolo della domanda, stai chiedendo di testare l'unità httpClint, prendendo in giro un FakeHttpClient può aiutarti a testare l'unità di altre parti di app eccetto httpClient, ma non aiuta nulla per il test di unità httpClient. Quello di cui hai bisogno è un FakeHttpLayer per il test delle unità httpClient (nessun server remoto, la rete richiede, quindi il test delle unità).

HttpClient manichino di prova:

Se avete solo bisogno di esaminare il comportamento applicazione nella situazione che internet è perso, quindi un classico Android strumento di prova è sufficiente, è possibile a livello di codice trasformare Internet nell'emulatore off durante l'esecuzione il test:

public void testWhenInternetOK() { 
    ... ... 
    webReader.readWebResource(); 
    // expect HTTP 200 response. 
    ... ... 
} 

public void testWhenInternetLost() { 
    ... ... 
    wifiManager = (WifiManager) this.getSystemService(Context.WIFI_SERVICE); 
    wifiManager.setWifiEnabled(false); 
    webReader.readWebResource(); 
    // expect no HTTP response. 
... ... 
} 

Ciò richiede il server HTTP remoto è completamente messa a punto e in uno stato di lavoro, e ogni volta che si esegue il classe di test, una vera e propria comunicazione HTTP è realizzato sulla rete e ha colpito sul server HTTP.

HttpClient test avanzato:

Se si desidera verificare il comportamento applicazione più precisamente, per esempio, si vuole testare una chiamata http in voi app per vedere se è gestire la risposta http diverso modo corretto. il Robolectric è la scelta migliore. Puoi utilizzare FakeHttpLayer e prendere in giro la richiesta e la risposta http con qualsiasi cosa tu voglia.

public void setup() { 
    String url = "http://..."; 
    // First http request fired in test, mock a HTTP 200 response (ContentType: application/json) 
    HttpResponse response1 = new DefaultHttpResponseFactory().newHttpResponse(HttpVersion.HTTP_1_1, 200, null); 
    BasicHttpEntity entity1 = new BasicHttpEntity(); 
    entity1.setContentType("application/json"); 
    response1.setEntity(entity1); 
    // Second http request fired in test, mock a HTTP 404 response (ContentType: text/html) 
    HttpResponse response2 = new DefaultHttpResponseFactory().newHttpResponse(HttpVersion.HTTP_1_1, 404, null); 
    BasicHttpEntity entity2 = new BasicHttpEntity(); 
    entity2.setContentType("text/html"); 
    response2.setEntity(entity2); 
    List<HttpResponse> responses = new ArrayList<HttpResponse>(); 
    responses.add(response1); 
    responses.add(response2); 
    Robolectric.addHttpResponseRule(new FakeHttpLayer.UriRequestMatcher("POST", url), responses); 
} 

public void testFoo() { 
    ... ... 
    webReader.readWebResource(); // <- a call that perform a http post request to url. 
    // expect HTTP 200 response. 
    ... ... 
} 

public void testBar() { 
    ... ... 
    webReader.readWebResource(); // <- a call that perform a http post request to url. 
    // expect HTTP 404 response. 
... ... 
} 

Alcuni professionisti di utilizzare Robolectric sono: prova

  • puramente JUnit, nessun test strumento in modo non è necessario avviare l'emulatore (o dispositivo reale) per eseguire il test, aumentare la velocità di sviluppo.
  • Ultima riga di codice di supporto Robolectric per abilitare/disabilitare FakeHttpLayer, in cui è possibile impostare la richiesta http da interpretare da FakeHttpLayer (nessuna vera chiamata http su rete), o impostare la richiesta http bypassare FakeHttpLayer (eseguire una vera chiamata http su Rete). Controlla this SO question per maggiori dettagli.

Se si controlla la sorgente di Robolectric, è possibile vedere che è abbastanza complesso implementare correttamente un FakeHtppLayer. Consiglierei di utilizzare il framework di test esistente invece di implementare la tua API.

Spero che questo aiuti.

+0

Grazie per la risposta. Bene, il titolo dice sull'unità che collauda una classe che usa HttpClient, non intendevo testare lo stesso HttpClient. Scusa, se non l'avessi chiarito. L'opzione con il gestore WiFi è ottima, ma il telefono continua a connettersi tramite la rete mobile. Ho provato una modalità aereo, è ancora in connessione. Quindi, suppongo, Robolectric sia l'unica scelta. Grazie. –