Используйте mock db при тестировании с Robolectric и ORMLite.

Я работаю над приложением для Android, которое использует OrmLiteSqliteOpenHelper для подключения к базе данных SQLite.

public class MyDatabaseHelper extends OrmLiteSqliteOpenHelper {
    ...

    private static final String DATABASE_NAME = "mydb.sqlite";
    private static MyDatabaseHelper helper = null;

    private MyDatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, BuildConfig.DATABASE_VERSION);
    }

    public static synchronized MyDatabaseHelper getHelper(Context context) {
        if (helper == null) {
            helper = new MyDatabaseHelper(context);
        }
        return helper;
    }
}

Для извлечения данных из базы данных у меня есть несколько классов провайдеров, они используют некоторые DAO.

public class ProductsProvider {

    public static List<Products> getProducts(Context context) {
        MyDatabaseHelper helper = MyDatabaseHelper.getHelper(context);
        Dao<Product, String> daoProducts = helperDatabase.getProductDao();
        ...
        ...
        ...
    }
}

У меня есть Robolectric для тестирования моего кода, но мне трудно понять, как использовать Robolectric вместе с ORMLite. Моя идея состоит в том, чтобы иметь фиктивный файл database.sqlite, предварительно заполненный той же структурой и данными, которые у меня обычно есть, и использовать его для всех моих тестов. Например, если я хочу протестировать класс ProductsProvider, я должен сделать следующее:

@RunWith(MyTestRunner.class)
public class ProductsProviderTest extends MyTestCase {

    @Test
    public void testDb() {
        List<Products> products = ProductsProvider.getProducts(getTestContext());
        assertNotNull(products);
        assertFalse(products.isEmpty());
    }
}

Обратите внимание, что ProductsProvider.getProducts() будет использовать MyDatabaseHelper, который будет использовать базу данных в стандартном расположении приложения Android, а не в моем локальном файле. Как изменить мой код для тестов, чтобы тесты с использованием локальной базы данных добавлялись в качестве актива или ресурса, не касаясь реального кода приложения?


person Nicola    schedule 17.02.2015    source источник
comment
Эти ответы помогают? Кажется, похожая проблема ="как узнать, работает ли мое приложение с robolectric"> stackoverflow.com/questions/28321961/   -  person Alex Florescu    schedule 17.02.2015
comment
Не очень, я не хочу реализовывать последнее предложенное решение, а с комментарием под ним непонятно, как ему удалось решить проблему. Даже если я создам новый класс MyDatabaseHelperTest в тестах, я не вижу, как я могу переопределить класс в основном коде, поскольку мой ProductsProvider использует класс в основном коде.   -  person Nicola    schedule 17.02.2015
comment
Ответ, который я имел в виду конкретно, был ответом Евгения. Вы можете создать приложение TestApplication, которое заберет Robolectric, и там вы можете инициализировать вспомогательную базу данных специально для загрузки данных, необходимых для ваших тестов.   -  person Alex Florescu    schedule 17.02.2015
comment
В любом случае мне придется изменить основной код... Я хотел посмотреть, нашел ли кто-нибудь другое решение для этого. Но все же... мой экземпляр БД будет в классе Application... как мне его использовать в моем помощнике?   -  person Nicola    schedule 17.02.2015


Ответы (2)


Вот как мы это делаем.

  1. Мы помещаем образец файла БД в папку src/test/res
  2. Мы запускаем следующий код перед тестом БД:

    private void copyTestDatabase( String resourceDBName )
        throws URISyntaxException, IOException
    {
        String filePath = getClass().getResource( resourceDBName ).toURI().getPath();
    
        String destinationPath = new ContextWrapper( Robolectric.application.getApplicationContext() ).getDatabasePath(
            DatabaseHelper.DATABASE_NAME ).getAbsolutePath();
    
        Files.copy( new File( filePath ), new File( destinationPath ) );
    } 
    

Будьте осторожны, так как эти тесты очень длинные

person Eugen Martynov    schedule 18.02.2015
comment
Спасибо! Что ты имеешь в виду под супердлинным? С точки зрения времени? Сложность кода? - person Nicola; 18.02.2015
comment
Я имел ввиду сроки. Иногда это занимает до 7 секунд - person Eugen Martynov; 18.02.2015

Для тех, кто не может выдержать 6-12-секундное время запуска Robolectric 3 + Gradle, следующее работает со встроенными в Android тестами JUnit4 (DbHelper extends OrmLiteSqliteOpenHelper).

@RunWith(AndroidJUnit4.class)
public class DbTest {

    private DbHelper dbHelper;

    @Before
    public void setUp() throws Exception {
        Context context = new RenamingDelegatingContext(
                InstrumentationRegistry.getTargetContext(), "test_");
        dbHelper = new DbHelper(context);
    }
}

Вероятно, вы могли бы сделать много оптимизаций, но я могу запустить небольшой пакет с большим объемом операций ввода-вывода, который каждый раз стирает базу данных на GenyMotion за 2,5 секунды.

Если вы не были в курсе последних новостей, я определенно рекомендую проверить, что Google недавно сделал со своими функциями тестирования. Введение на сайте Robolectric на данный момент является откровенной ложью.

person Jimeux    schedule 13.05.2015