Я пытаюсь использовать Robolectric для тестирования своего приложения для Android, но столкнулся с проблемой тестирования, которую я не могу понять.

Я тестирую Activity, который расширяет мой класс BaseActivity и использует RxAndroid, этот класс выглядит так:

public abstract class BaseActivity extends AppCompatActivity {
    protected final SharedService sharedService = MyApplication.getInstance().getSharedService();

    protected Activity getActivity() {
        return this;
    }
}

Как видите, он получает объект sharedService из моего базового класса Application.

Затем в своей деятельности я ссылаюсь на этот код следующим образом:

//...
        Subscription s = sharedService.login(params)
            .compose(ObservableUtils.<JsonObject>applySchedulers())
            .subscribe(new Action1<JsonObject>() {
                @Override
                public void call(JsonObject jsonObject) {
                    //...
                }
            }, new Action1<Throwable>() {
                @Override
                public void call(Throwable throwable) {
                    //...
                }
            });

    subscriptions.add(s);

//..

Таким образом, Activity напрямую ссылается на переменную sharedService из BaseActivity для доступа к ней и вызова метода объекта SharedService. Он использует RxAndroid для получения наблюдаемого.

Код в вызове Retrofit выглядит следующим образом:

@POST("/login")
Observable<JsonObject> login(
        @Body JsonObject body) ;

Проблема в том, что когда я прихожу для тестирования с помощью Robolectric, я получаю исключение с нулевым указателем в Activity, когда вызывается код RxAndroid.

Мой тест выглядит следующим образом:

@Config(constants = BuildConfig.class)
@RunWith(TestRunner.class)
public class MyActivityTest{

@Mock
private SharedService mockSharedService;

@Before
    public void setup() {
        // Convenience method to run Activity through the Activity Lifecycle methods:
        // onCreate(...) => onStart() => onPostCreate(...) => onResume()

        MockitoAnnotations.initMocks(this);

        TestMyApplication testMyApp = (TestMyApplication) TestCompanionApplication.getInstance();
        testMyApp.setSharedService(this.mockSharedService); //Set our Mocked application class to use our mocked API

        //Build our activity using Robolectric
        ActivityController<MyActivity> controller = Robolectric.buildActivity(MyActivity.class);
        activity = controller.get();

        controller.create(); //Create out Activity

        //..Get views
}

@Test
public void testService(){

    btnTest.click(); //This fires the service call
    Mockito.verify(this.mockSharedService).login((JsonObject) Mockito.any());

}

Когда я запускаю этот тест, я получаю исключение NullPointerException.

Итак, я знаю, что мне каким-то образом нужно заставить Activity использовать фиктивный API, который я установил для класса TestMyApplication, но поскольку BaseActivity создает переменную, которая содержит это, а затем другие мои действия ссылаются на это, как мне сделать это с помощью Robolectric?

1
Donal Rafferty 24 Июн 2016 в 12:51
Почему вы работаете с JsonObject, а не с POJO? В этом прелесть дооснащения .
 – 
Eugen Martynov
24 Июн 2016 в 16:44

1 ответ

Лучший ответ

Исправить довольно просто:

when(mockSharedService.login(any())).thenReturn(Observable.just(new JsonObject()));

Но, вероятно, он потерпит неудачу позже, когда вы попытаетесь обработать полученный json.

1
Eugen Martynov 24 Июн 2016 в 16:43
1
Вы имитируете службу, и по умолчанию она возвращает null, когда вы начинаете связывать подписку. Это вызывает NPE. Я заглушил этот вызов, поэтому он возвращает Observable, который выдаст один JsonObject при подписке
 – 
Eugen Martynov
24 Июн 2016 в 17:07