Използвайте макет db, когато тествате с Robolectric и ORMLite

Работя върху приложение за Android, което използва OrmLiteSqliteOpenHelper за свързване към SQLite db.

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

За да извлека данни от db, имам някои класове на доставчици, те използват някои 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. Идеята ми е да имам макетна база данни.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, който ще използва db в стандартното местоположение на приложението за Android, а не моя локален файл. Как мога да модифицирам кода си за тестовете, така че тестовете да използват локална база данни, добавени като актив или ресурс, без да докосвам истинския код на приложението?


person Nicola    schedule 17.02.2015    source източник
comment
Помагат ли тези отговори? Изглежда, че има подобен проблем stackoverflow.com/questions/28321961/   -  person Alex Florescu    schedule 17.02.2015
comment
Не наистина, не искам да прилагам последното предложено решение и с коментара под него не е ясно как е успял да разреши проблема. Дори и да създам нов клас MyDatabaseHelperTest в тестовете, не виждам как мога да заместя този в основния код, тъй като моят ProductsProvider използва този в основния код.   -  person Nicola    schedule 17.02.2015
comment
Отговорът, който имах предвид конкретно, беше на Eugen. Можете да създадете TestApplication, което Robolectric ще вземе и там можете да инициализирате помощник на базата данни специално, за да заредите данните, от които се нуждаете за вашите тестове.   -  person Alex Florescu    schedule 17.02.2015
comment
Във всеки случай ще трябва да променя основния код... Исках да видя дали някой е намерил друго решение за това. Но все пак... екземплярът ми на DB ще бъде в класа Application... как да го използвам тогава в моя помощник?   -  person Nicola    schedule 17.02.2015


Отговори (2)


Ето как го правим.

  1. Поставяме примерен DB файл в папка src/test/res
  2. Изпълняваме следващия код преди DB тест:

    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, следното работи с вградените JUnit4 тестове на Android (DbHelper разширява 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);
    }
}

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

Ако не сте били в крак с него, определено препоръчвам да проверите какво направи Google с функциите си за тестване наскоро. Въведението на сайта Robolectric на този етап е чиста лъжа.

person Jimeux    schedule 13.05.2015