2016-08-03 7 views
10

Ich versuche, getJsonFromResource zu testen, die loadNewsFeed ruft. Ich möchte in der Lage sein, 2 Fälle 1 zu testen, wobei loadNewsFeed eine leere Zeichenfolge zurückgibt und die andere, wo es eine JSON-Zeichenfolge zurückgibt.Verwenden von Mockito, um die Funktion zu testen, die einen Kontext verwendet

Also versuche ich die loadNewsFeed Funktion zu verspotten, um eine leere Zeichenfolge zurückzugeben. Wenn der konkrete getJsonFromResource jedoch aufgerufen wird, wird es das echte loadNewsFeed aufrufen und eine Nullzeiger-Ausnahme verursachen. Dies ist, was ich in meinem Test Kommentar versucht habe, zu erklären, was ich tue:

@Test 
public void shouldFailIfJSONStringIsEmpty() throws Exception { 
    /* Mock Context class */ 
    Context context = mock(Context.class); 
    /* initialize the concrete parseNewsFeed passing in the fake context */ 
    ParseNewsFeed parseNewsFeed = new ParseNewsFeed(context); 
    /* Create a mock of the parseNewsFeed so a fake call to loadNewsFeed will return an empty string */ 
    ParseNewsFeed mockParseNewsFeed = mock(ParseNewsFeed.class); 
    /* Mock the events that will be verified */ 
    ParseNewsFeedContract.Events<Status> mockEvents = mock(ParseNewsFeedContract.Events.class); 

    /* Return an empty string when loadNewsFeed is called */ 
    when(mockParseNewsFeed.loadNewsFeed()).thenReturn(""); 

    /* Called the concrete getJsonFromResource */ 
    parseNewsFeed.getJsonFromResource(mockEvents); 

    /* verify that onNewsFailure was called once and onNewsSuccess was never called */ 
    verify(mockEvents, times(1)).onNewsFailure(anyString()); 
    verify(mockEvents, never()).onNewsSuccess(any(Status.class)); 
} 

Dies ist die Klasse I zu testen, versuchen.

public class ParseNewsFeed implements ParseNewsFeedContract { 
    private Context mContext; 

    public ParseNewsFeed(Context context) { 
     if(context != null) { 
      Timber.d("mContext != null"); 
      mContext = context; 
     } 
    } 

    /** 
    * Get the json from the local resource file and add to the cache to save loading each time 
    * @return the json in string representation 
    */ 
    @Override 
    public void getJsonFromResource(Events<Status> events) { 
     /* Get the json in string format */ 
     final String jsonString = loadNewsFeed(); 

     /* Check that is contains something */ 
     if(!jsonString.isEmpty()) { 
      try { 
       final Status status = new Gson().fromJson(jsonString, Status.class); 
       if(status != null) { 
        Timber.d("url: %s", status.getResults().get(0).getMultimedia().get(0).getUrl()); 
        events.onNewsSuccess(status); 
       } 
       else { 
        Timber.e("status == null"); 
        events.onNewsFailure("Failed to get results from json"); 
       } 
      } 
      catch (JsonSyntaxException e) { 
       Timber.e("Invalid JSON: %s", e.getMessage()); 
       events.onNewsFailure(e.getMessage()); 
      } 
     } 
    } 

    /** 
    * Opens and reads from the news_list and writes to a buffer 
    * @return return the json representation as a string or a empty string for failure 
    */ 
    public String loadNewsFeed() { 
     InputStream inputStream = mContext.getResources().openRawResource(R.raw.news_list); 
     Writer writer = new StringWriter(); 
     char[] buffer = new char[1024]; 

     try { 
      InputStreamReader inputReader = new InputStreamReader(inputStream, "UTF-8"); 
      BufferedReader bufferReader = new BufferedReader(inputReader); 
      int n; 
      while ((n = bufferReader.read(buffer)) != -1) { 
       writer.write(buffer, 0, n); 
      } 

      inputStream.close(); 
     } 
     catch (IOException ioException) { 
      return ""; 
     } 

     return writer.toString(); 
    } 
} 

Antwort

3

Es sieht aus wie Sie ein ParseNewsFeed Objekt, in dem die loadNewsFeed Methode Stub wurde haben wollen, aber auch andere Methoden korrekt funktionieren. Der einfachste Weg, das zu bekommen, würde wahrscheinlich einen Spion zu schaffen sein, so etwas wie

ParseNewsFeed spyParseNewsFeed = Mockito.spy(new ParseNewsFeed(context)); 
Mockito.doReturn("").when(spyParseNewsFeed).loadNewsFeed(); 
5

Zunächst einmal ist der Grund, warum Ihr Original-Code nicht funktioniert, ist, weil es keine Beziehung zwischen zwei Objekten parseNewsFeed und mockParseNewsFeed, Daher hat der Stubbing, den Sie für die mockParseNewsFeed tun keine Wirkung, wenn Sie parseNewsFeed.getJsonFromResource(mockEvents) aufrufen. Die Verwendung von spy, wie David Wallace vorgeschlagen hat, würde funktionieren, aber wenn ich Sie wäre, würde ich den Code etwas anders schreiben, um es noch einfacher zu testen.

Eine Beobachtung ist, dass der Code in loadNewsFeed() Methode nicht eine starke Beziehung mit der ParseNewsFeed Klasse zu haben scheint, so würde ich diesen Code in ein Objekt extrahieren (zB NewsFeedLoader), und dann habe diese Aufgabe als eine Abhängigkeit von ParseNewsFeed Klasse. Dann können Sie diese Loader leicht spotten (geben Sie "" oder irgendeine Schnur zurück, die Sie wünschen, wenn Sie eine Context und möglicherweise die R.raw.news_list Identifikation auch übergeben). Mit dieser Loader Klasse können Sie es sogar Unit-Test separat von der ParseNewsFeed, und in der Lage, verbessern die Loader wie Sie wollen (z. B. eine bessere Möglichkeit, eine rohe Ressource zu lesen), ohne die Klasse ParseNewsFeed.

3

Verwenden Sie when() und then() Methoden Ihres gespotteten Kontext. Es ist tatsächlich in Beispiel official tutorial here.

@Mock 
Context mMockContext; 

@Test 
public void readStringFromContext_LocalizedString() { 
    // Given a mocked Context injected into the object under test... 
    when(mMockContext.getString(R.string.hello_word)) 
      .thenReturn(FAKE_STRING); 
    ClassUnderTest myObjectUnderTest = new ClassUnderTest(mMockContext); 

    // ...when the string is returned from the object under test... 
    String result = myObjectUnderTest.getHelloWorldString(); 

    // ...then the result should be the expected one. 
    assertThat(result, is(FAKE_STRING)); 
beschrieben
Verwandte Themen