возможно ли заменить MediaStore на тестовый дубль с помощью robolectric?

#android #android-contentprovider #robolectric #android-contentresolver

#Android #android-contentprovider #robolectric #android-contentresolver

Вопрос:

У меня есть класс, который запрашивает хранилище мультимедиа для изображений. Например, у меня есть код, который выглядит как someContentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, ... ) . Я хочу проверить, что, помимо прочего, мои запросы к MediaStore верны.

Что я сделал до сих пор в своем тесте, так это:

 ContentResolver resolver = new Activity().getContentResolver();
ContentValues values = new ContentValues();
values.put( MediaStore.Images.Media.DATA,
            "/fake/path/file1.jpg" );
values.put( MediaStore.Images.Media.DATE_ADDED,
            fakeTime.getTime() );
resolver.insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                 values );
  

Я внедряю этот преобразователь в свой класс, который выполняет запрос к нему. Однако запрос возвращает null. Я видел этот пост:http://ikaruga2.wordpress.com/2013/07/29/roboelectric-and-contentresolverscontentproviders / в котором говорится о регистрации поставщика контента с использованием ShadowContentResolver, так что, что-то вроде:

 ShadowContentResolver.registerProvider( MediaStore.AUTHORITY, <SOMETHING_GOES_HERE> );
  

но я не знаю, что указать для поставщика контента. Может быть, использовать MediaStore объект? Нет, это не ContentProvider . Возможно, это MediaProvider ? По какой-то причине символ не может быть разрешен.

На данный момент у меня есть серьезные сомнения в том, что это даже отдаленно правильный подход. Может ли кто-нибудь направить меня в правильном направлении?

используя Robolectric 2.4 snapshot и API 19.

Комментарии:

1. Вы уже нашли решение?

2. @SebastianRoth нет, у меня нет.

Ответ №1:

Вы можете полагаться на ShadowContentResolver.setCursor(Uri, BaseCursor) и RoboCursor для создания тестовых данных и проверки запроса. RoboCursor не обеспечивает полной реализации нескольких методов, поэтому вы можете либо переопределить и проигнорировать их, либо сделать что-то значимое. RoboCursor расширяет BaseCursor , переопределяя setQuery() позволяет перехватывать запросы и проверять или что-то там делать. Используя Robolectric 3.0.

 RoboCursor cursor = new RoboCursor() {
    @Override
    public void registerContentObserver(ContentObserver observer) {
        // no op
    }

    @Override
    public void unregisterContentObserver(ContentObserver observer) {
        // no op
    }

    @Override
    public void registerDataSetObserver(DataSetObserver observer) {
        // no op
    }

    @Override
    public void unregisterDataSetObserver(DataSetObserver observer) {
        // no op
    }

    @Override
    public boolean isClosed() {
        return true;
    }
};
cursor.setColumnNames(Arrays.asList(MediaStore.Images.Media._ID,
        MediaStore.Images.Media.BUCKET_DISPLAY_NAME));
cursor.setResults(new Object[][]{
        new Object[]{1L, "WhatsApp"},
        new Object[]{2L, "Photos"},
        new Object[]{3L, "WhatsApp"}
});
shadowOf(ShadowApplication.getInstance().getContentResolver())
        .setCursor(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, cursor);
  

Ответ №2:

У меня была аналогичная проблема с MediaStore, в моем случае класс пытался получить доступ к MediaStore через управляемый запрос. При запуске теста, который проходил по такому кодовому пути, тест завершился неудачно с NPE, поскольку запрос вернул null, как и в вашем случае.

Метод, вызывающий нарушение

 public String getPath(Uri uri, Activity activity) {
    String[] projection = { MediaColumns.DATA };
    Cursor cursor = activity
            .managedQuery(uri, projection, null, null, null);
    int column_index = cursor.getColumnIndexOrThrow(MediaColumns.DATA);
    cursor.moveToFirst();
    return cursor.getString(column_index);
}
  

Учитывая, что вы уже внедряете (я внедряю зависимости с помощью Dagger в свой проект) распознаватель, вы можете либо издеваться над ним, если это вас устраивает (например, через Mockito), либо частично издеваться над ним, поэтому метод-нарушитель по умолчанию использует возвращаемое значение.

 PhotoUtilities pu=Mockito.spy(new PhotoUtilities());
Mockito.doReturn(Constants.getDataDir().getAbsolutePath() "/aaa.txt").
when(pu).getPath(Mockito.isA(Uri.class), Mockito.isA(Activity.class));  
  

Таким образом, при попытке запуска теста getPath() запрос не выполнялся, а использовалось возвращаемое значение по умолчанию, установленное в частичном макете, что позволяло продолжить тест.

Я знаю, что это может быть не совсем то, что вы ищете, но это может удовлетворить ваши потребности, как это было для меня.

Комментарии:

1. Я действительно хочу проверить запрос. Тем не менее, спасибо за ответ!