Question

Je l'ai mis en place l'accès à une base de données en utilisant SQLiteOpenHelper du package android.database au sein de certaines classes (avec motif DAO).

J'ai écrit quelques tests JUnit pour ces classes à l'aide d'un AndroidTestCase mais cela provoque les tests à utiliser comme l'application de la même base de données.

Je lis que le ProviderTestCase2 ou RenamingDelegatingContext peuvent être utilisés pour tester la base de données séparément. Malheureusement je ne pouvais pas trouver un beau tutoriel / exemple qui montre comment tester une base de données avec ProviderTestCase2 / RenamingDelegatingContext.

point Quelqu'un peut-il me quelque part ou me donner un pourboire ou partager un peu de code pour les tests de base de données?

Cheeerrrrsss !! Giorgio

Était-ce utile?

La solution

Les deux ProviderTestCase et RenamingDelegatingContext détruira la base de données si l'on existe déjà avant de l'ouvrir dans le contexte de, donc dans ce sens, ils ont tous deux la même approche de bas niveau vers l'ouverture d'une base de données SQLite.

tirer parti en ouvrant la base de données dans votre appareil dans setUp(), qui sera ensuite faire en sorte que votre travail avec une nouvelle base de données avant chaque test.

Je suggère que vous allez écrire pour les fournisseurs de contenu plutôt que de créer des cartes de base de données. Vous pouvez utiliser une interface commune pour l'accès aux données, que ce soit stockée dans la DB ou quelque part sur le réseau, la conception des fournisseurs de contenu peuvent être logés à accéder à ces données au prix d'un peu de IPC frais généraux impliqués que la plupart d'entre nous shouldn » t doivent se soucier.

Si vous avez fait cela pour accéder à une base de données SQLite, le cadre gérerait complètement la connexion de base de données pour vous dans un processus séparé. Comme le boeuf ajouté, le ProviderTestCase2<ContentProvider> Bootstraps complètement un contexte de test pour votre fournisseur de contenu sans avoir à écrire une seule ligne de code.

Mais ce n'est pas dit que ce n'est pas un énorme effort pour faire le bootstrapping vous. Donc, en supposant que vous aviez un adaptateur de base de données en tant que telle; nous allons concentrer sur open() pour obtenir un accès en écriture à notre base de données, rien d'extraordinaire:

public class MyAdapter {

    private static final String DATABASE_NAME = "my.db";
    private static final String DATABASE_TABLE = "table";
    private static final int DATABASE_VERSION = 1;


    /**
     * Database queries
     */
    private static final String DATABASE_CREATE_STATEMENT = "some awesome create statement";

    private final Context mCtx;
    private SQLiteDatabase mDb;
    private DatabaseHelper mDbHelper;

    private static class DatabaseHelper extends SQLiteOpenHelper {

        public DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(DATABASE_CREATE_STATEMENT);  
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int a, int b) {
            // here to enable this code to compile
        }
    }

    /**
     * Constructor - takes the provided context to allow for the database to be
     * opened/created.
     * 
     * @param context the Context within which to work.
     */
    public MyAdapter(Context context) {
        mCtx = context;
    }

    /**
        * Open the last.fm database. If it cannot be opened, try to create a new
        * instance of the database. If it cannot be created, throw an exception to
        * signal the failure.
        * 
        * @return this (self reference, allowing this to be chained in an
        *         initialization call)
        * @throws SQLException if the database could be neither opened or created
        */
    public MyAdapter open() throws SQLException {
        mDbHelper = new DatabaseHelper(mCtx);
        mDb = mDbHelper.getWritableDatabase();
        return this;
    }

    public void close() {
            mDbHelper.close();
        }

}

Ensuite, vous pouvez écrire votre test en tant que tel:

public final class MyAdapterTests extends AndroidTestCase {

    private static final String TEST_FILE_PREFIX = "test_";
private MyAdapter mMyAdapter;

@Override
protected void setUp() throws Exception {
    super.setUp();

    RenamingDelegatingContext context 
        = new RenamingDelegatingContext(getContext(), TEST_FILE_PREFIX);

    mMyAdapter = new MyAdapter(context);
    mMyAdapter.open();
}

@Override
protected void tearDown() throws Exception {
    super.tearDown();

    mMyAdapter.close();
    mMyAdapter = null;
}

public void testPreConditions() {
    assertNotNull(mMyAdapter);
}

}

Alors qu'est-ce qui se passe ici est que la mise en œuvre du cadre de RenamingDelegatingContext, une fois MyAdapter(context).open() est appelé, va recréer toujours la base de données. Chaque test que vous écrivez maintenant sera va à l'encontre de l'état de la base de données après MyAdapter.DATABASE_CREATE_STATEMENT est appelée.

Autres conseils

Je réellement utiliser la base de données avec SQLiteOpenHelper et j'ai un truc pour tester. L'idée est d'utiliser le standard sur fichier stocké DB lors de l'utilisation normale de l'application et une base de données en mémoire lors des tests. De cette façon, vous pouvez utiliser un DB clair pour chaque test sans données insertion / suppression / mise à jour dans votre base de données standard. Cela fonctionne très bien pour moi.

Gardez à l'esprit que vous pouvez utiliser la base de données en mémoire, juste passer null comme nom de fichier de base de données. Ceci est clairement documenté dans la documentation de l'API.

Avantages de l'utilisation DB en mémoire lors des tests est expliqué ici: https: // attakornw .wordpress.com / 2012/02/25 / utilisant en mémoire sqlite-base de données en android tests /

Dans mon projet, j'ai la classe DBHelper Wich étend SQLiteHelper. Comme vous pouvez le voir, il y a les méthodes standard. J'ai simplement ajouté un constructeur avec deux paramètres. La différence est que quand je l'appelle le constructeur super, je passe null comme nom DB.

public class DBHelper extends SQLiteOpenHelper {

    public static final int DATABASE_VERSION = 1;
    public static final String DATABASE_NAME = "mydatabase.db";

    public DBHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    public DBHelper(Context context, boolean testMode) {
        super(context, null, null, DATABASE_VERSION);
    }

    public void onCreate(SQLiteDatabase db) {
        //create statements
    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //on upgrade policy
    }

    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        //on downgrade policy
    }
}

Chaque « modèle » dans le projet étend DBModel qui est une classe abstraite.

public abstract class DBModel {
    protected DBHelper dbhelper;

    public DBModel(Context context) {
        dbhelper = new DBHelper(context);
    }

    //other declarations and utility function omitted

}

Comme nous l'avons ici: Comment puis-je savoir si le code est en cours d'exécution dans un test JUnit ou non? il existe un moyen d'établir si vous exécutez les tests JUnit, la simple recherche en oligo-éléments pile. En tant que conseguence, je constructeur DBModel modifié

public abstract class DBModel {
    protected DBHelper dbhelper;

    public DBModel(Context context) {
        if(isJUnitTest()) {
            dbhelper = new DBHelper(context, true);
        } else {
            dbhelper = new DBHelper(context);
        }
    }

    private boolean isJUnitTest() {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        List<StackTraceElement> list = Arrays.asList(stackTrace);
        for (StackTraceElement element : list) {
            if (element.getClassName().startsWith("junit.")) {
                return true;
            }
        }
        return false;
    }

    //other declarations and utility function omitted

}

Notez que

startsWith("junit.")

peut être

startsWith("org.junit.")

dans votre cas.

I ai une application qui utilise un ContentProvider soutenu par une base de données sqlite pour fournir des données à l'application.

Soit PodcastDataProvider être la dataprovider réelle utilisée par l'application.

Ensuite, vous pouvez mettre en place un fournisseur de test avec quelque chose comme ce qui suit:

public abstract class AbstractPodcastDataProvider extends ProviderTestCase2<PodcastDataProvider>{
    public AbstractPodcastDataProvider(){
        this(PodcastDataProvider.class, Feed.BASE_AUTH);
    }

    public AbstractPodcastDataProvider(Class<PodcastDataProvider> providerClass,
            String providerAuthority) {
        super(providerClass, providerAuthority);
    }

    public void setUp() throws Exception{
        super.setUp();

        //clear out all the old data.
        PodcastDataProvider dataProvider = 
            (PodcastDataProvider)getMockContentResolver()
            .acquireContentProviderClient(Feed.BASE_AUTH)
            .getLocalContentProvider();
        dataProvider.deleteAll();
    }
}

pour configurer un fournisseur de données de test qui sera soutenu par une autre base de données que l'application réelle.

Pour tester le DAO, créer une autre classe qui étend AbstractPodcastDataProvider et utilisez la balise

getMockContentResolver();

méthode pour obtenir une instance d'un résolveur contenu qui utilisera la base de données de test au lieu de la base de données de l'application.

private static String db_path = "/data/data/android.testdb/mydb";
private SQLiteDatabase sqliteDatabase = null;
private Cursor cursor = null;
private String[] fields;

/*
 * (non-Javadoc)
 * 
 * @see dinota.data.sqlite.IDataContext#getSQLiteDatabase()
 */
public SQLiteDatabase getSQLiteDatabase() {
    try {

        sqliteDatabase = SQLiteDatabase.openDatabase(db_path, null,
                SQLiteDatabase.OPEN_READWRITE);
        sqliteDatabase.setVersion(1);
        sqliteDatabase.setLocale(Locale.getDefault());
        sqliteDatabase.setLockingEnabled(true);
        return sqliteDatabase;
    } catch (Exception e) {
        return null;
    }

}

si vous donnez l'emplacement exact de la sqlite db (dans mon cas, il est db_path), en utilisant la méthode ci-dessus, vous trouverez-out si elle retourne un SQLiteDatabase ou non.

Une solution possible peut être à la base de données ouverte en utilisant cette méthode

myDataBase = SQLiteDatabase.openDatabase(DATABASE_NAME, null, SQLiteDatabase.OPEN_READWRITE);

nom de la base de changements dans vos tests. vous pouvez trouver quelques informations sur cette méthode.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top