在我的测试类中模拟一个方法

时间:2017-07-02 15:01:20

标签: mockito

Android Studio 2.3

我想在模型类中测试以下方法:

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();
    }
}
}

在我的测试类中,我正在测试:

  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();
    }
}

然而,问题是我的模型类中的Subscription始终为null,因此永远不会输入if blook。有没有办法用Mockito或spys进行测试?

非常感谢任何建议,

1 个答案:

答案 0 :(得分:1)

你应该测试recipeListModel类,你有shutdown()方法,将mock设置为这个类。

如果你没有在recipeListModel或构造函数param ....中设置set方法,你可以使用如下反射设置模拟对象:

@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();
}
更新后

如果你不能改变创作方式,你应该嘲笑它(完全创作方式),我不知道你的api,所以这只是想法:

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);