2017-07-02 4 views
0
Android Studio 2.3 

Ich habe folgende Methode, die ich in meinem Modell Klasse testen will:Mocking eine Methode in meiner Testklasse

public class RecipeListModelImp implements RecipeListModelContract { 

    private Subscription subscription; 
    private RecipesAPI recipesAPI; 
    private RecipeSchedulers recipeSchedulers; 

@Inject 
public RecipeListModelImp(@NonNull RecipesAPI recipesAPI, @NonNull RecipeSchedulers recipeSchedulers) { 
    this.recipesAPI = Preconditions.checkNotNull(recipesAPI); 
    this.recipeSchedulers = Preconditions.checkNotNull(recipeSchedulers); 
} 

@Override 
public void getRecipesFromAPI(final RecipeGetAllListener recipeGetAllListener) { 
    subscription = recipesAPI.getAllRecipes() 
      .subscribeOn(recipeSchedulers.getBackgroundScheduler()) 
      .observeOn(recipeSchedulers.getUIScheduler()) 
      .subscribe(new Subscriber<List<Recipe>>() { 
       @Override 
       public void onCompleted() { 
       } 

       @Override 
       public void onError(Throwable e) { 
        recipeGetAllListener.onRecipeGetAllFailure(e.getMessage()); 
       } 

       @Override 
       public void onNext(List<Recipe> recipe) { 
        recipeGetAllListener.onRecipeGetAllSuccess(recipe); 
       } 
      }); 
} 

@Override 
public void shutdown() { 
    if(subscription != null && !subscription.isUnsubscribed()) { 
     subscription.unsubscribe(); 
    } 
} 
} 

In meiner Test-Klasse I wie diese Prüfung am:

public class RecipeListModelImpTest { 

    @Mock Subscription subscription; 
    @Mock RecipesAPI recipesAPI; 
    @Mock RecipeListModelContract.RecipeGetAllListener recipeGetAllListener; 
    @Mock List<Recipe> recipes; 

    @Inject RecipeSchedulers recipeSchedulers; 

    private RecipeListModelContract recipeListModel; 

    @Before 
    public void setup() { 

     TestBusbyComponent testBusbyComponent = DaggerTestBusbyComponent.builder() 
       .mockRecipeSchedulersModule(new MockRecipeSchedulersModule()) 
       .build(); 

     testBusbyComponent.inject(RecipeListModelImpTest.this); 

     MockitoAnnotations.initMocks(RecipeListModelImpTest.this); 
     recipeListModel = new RecipeListModelImp(recipesAPI, recipeSchedulers); 
    } 

    @Test(expected = NullPointerException.class) 
    public void testShouldThrowExceptionOnNullParameter() { 
     recipeListModel = new RecipeListModelImp(null, null); 
    } 

    @Test 
    public void testRecipeListModelShouldNotBeNull() { 
     assertNotNull(recipeListModel); 
    } 

    @Test 
    public void testShouldGetRecipesFromAPI() { 
     when(recipesAPI.getAllRecipes()).thenReturn(Observable.just(recipes)); 

     recipeListModel.getRecipesFromAPI(recipeGetAllListener); 

     verify(recipesAPI, times(1)).getAllRecipes(); 
     verify(recipeGetAllListener, times(1)).onRecipeGetAllSuccess(recipes); 
     verify(recipeGetAllListener, never()).onRecipeGetAllFailure(anyString()); 
    } 

    @Test 
    public void testShouldFailToGetRecipesFromAPI() { 
     when(recipesAPI.getAllRecipes()) 
       .thenReturn(Observable.<List<Recipe>>error(
         new Throwable(new RuntimeException("Failed to get recipes")))); 

     recipeListModel.getRecipesFromAPI(recipeGetAllListener); 

     verify(recipesAPI, times(1)).getAllRecipes(); 
     verify(recipeGetAllListener, times(1)).onRecipeGetAllFailure(anyString()); 
     verify(recipeGetAllListener, never()).onRecipeGetAllSuccess(recipes); 
    } 

    @Test 
    public void testShouldShutdown() { 
     when(subscription.isUnsubscribed()).thenReturn(false); 
     final Field subscriptionField; 

     try { 
      subscriptionField = recipeListModel.getClass().getDeclaredField("subscription"); 
      subscriptionField.setAccessible(true); 
      subscriptionField.set(recipeListModel, subscription); 
     } catch(NoSuchFieldException e) { 
      e.printStackTrace(); 
     } 
     catch(IllegalAccessException e) { 
      e.printStackTrace(); 
     } 

     recipeListModel.shutdown(); 

     verify(subscription, times(1)).unsubscribe(); 
    } 
} 

Das Problem ist jedoch, dass das Abonnement in meiner Modellklasse immer null ist, also niemals den if blook eingeben wird. Gibt es eine Möglichkeit, dies mit Mockito oder Spys zu testen?

Vielen Dank für Ihre Anregungen,

+1

Sicher. Machen Sie, was Sie getan haben, aber stellen Sie sicher, dass Sie das Mock-Abonnement in das Rezeptlisten-Modell injizieren. Ohne etwas über seinen Code zu wissen, ist es schwierig, präzise Ratschläge zu geben. –

Antwort

1

Sie sollten Test recipeListModel Klasse, in der Sie shutdown() Methode, setzen Mock in dieser Klasse haben.

Wenn Sie nicht Methode zur Zeichnung in recipeListModel festgelegt haben, oder Konstruktor param ....) Sie Mock-Objekt mit Reflexion wie einstellen:

@Test 
public void testShouldShutdown() { 
    Subscription subscription = mock(Subscription.class); 
    when(subscription.isUnsubscribed()).thenReturn(false); 

    Field subscriptionField = recipeListModel.getClass().getDeclaredField("subscription"); 
    subscriptionField.setAccessible(true); 
    subscriptionField.set(recipeListModel, subscriptionMock); 

    recipeListModel.shutdown(); 

    verify(subscription, times(1)).unsubscribe(); 
} 

nach dem Update:

wenn Sie nicht Art und Weise der Erstellung ändern können, sollten Sie es wie (volle Art und Weise der Schöpfung) verspotten, ich weiß nicht, Ihre api, so ist es nur Idee:

Subscription subscription = mock(Subscription.class); 
when(subscription.isUnsubscribed()).thenReturn(false); 

// preparation mock for create Subscription 
//for recipesAPI.getAllRecipes() 
Object mockFor_getAllRecipes = mock(....); 
when(recipesAPI.getAllRecipes()).thenReturn(mockFor_getAllRecipes); 

//for subscribeOn(recipeSchedulers.getBackgroundScheduler()) 
Object mockFor_subscribeOn = mock(); 
when(mockFor_getAllRecipes.subscribeOn(any())).thenReturn(mockFor_subscribeOn); 

//for .observeOn(recipeSchedulers.getUIScheduler()) 
Object mockFor_observeOn = mock(); 
when(mockFor_subscribeOn .observeOn(any())).thenReturn(observeOn); 


// for .subscribe 
when(observeOn.subscribe(any()).thenReturn(subscription); 
+0

+ sbavateam danke für die Antwort. Ich habe meine Fragen mit meinem kompletten Quellcode bearbeitet. Ich mag die Idee, die Methode zu setzen. Aber es macht den Code mit der Ausnahmebehandlung sehr hässlich. Gibt es einen anderen Weg, dies zu tun? Schauen Sie sich meine kompletten Klassen an? danke, – ant2009

+0

ich habe Idee hinzugefügt. Siehe meinen Bearbeitungsblock – xyz

+0

Danke für das Update. Das Mocking der API wurde jedoch bereits durchgeführt. Wie ich Mocks für getAllRecipes injiziere. Ich habe jedoch nur nach der Überprüfung der Subscription.unsubscribe() gefragt. Ich habe mich nur gefragt, ob es überhaupt so war. Aus diesem Grund habe ich meinen gesamten Code veröffentlicht, damit Sie das Gesamtbild sehen können. Ich habe mich gerade über alternative Lösung statt getDeclaredField ("...") -Methode gefragt. – ant2009

Verwandte Themen