読者です 読者をやめる 読者になる 読者になる

リア充爆発日記

You don't even know what ria-ju really is.

Robolectric + ormliteでUnitテスト

や。何もしなくてもよかった。。

どうやってやるのが常道なのかなぁ、とか2時間近く調べて、ShadowSQLiteOpenHelperが絡んでくるんだろうな、というところあたりまではわかったけど、具体的にどうするのかわからなかった。

が、前述のとおり、結局何もしなくてもRobolectricがよろしくやってくれるのだった。なんてこった。とりあえず書いてみろって話ですよ。

そういや、ormliteについてはAndroidでSQLiteを使おうとしたときの情報源まとめで名前を出したくらいで、具体的に何も書いてないけど、このエントリに書いてあるリンクで事足りると思う。

DatabaseHelper.java

public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
    private static final String TAG = DatabaseHelper.class.getSimpleName();

    private static final String DATABASE_DIR = Environment.getExternalStorageDirectory().getPath()
        + FileManager.SQLite_DB_HOGE;
    private static final int DATABASE_VERSION = 1;

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

    @Override
    public void onCreate(SQLiteDatabase database, ConnectionSource connectionSource) {
        try {
            Log.d(TAG, "create db table");
            TableUtils.createTableIfNotExists(connectionSource, Hoge.class);
        } catch (SQLException e) {
            Log.e(TAG, "Could NOT create database.");
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase database, ConnectionSource connectionSource, int oldVersion, int newVersion) {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    public void clearAllTable() {
        Log.d(TAG, "clear db data");

        try {
            ConnectionSource connectionSource = getConnectionSource();
            TableUtils.clearTable(connectionSource, Hoge.class);


            // TODO run on thread
            SQLiteDatabase db = getWritableDatabase();
            db.execSQL("vacuum");


        } catch (SQLException e) {
            Log.e(TAG, e.getMessage());
        }

    }
}

というヘルパーがあって、Hoge関連のDaoとかビーン的なものはOrmliteのいうがままに作ってあって、で、テストコードはこんな感じ。

@RunWith(RobolectricTestRunner.class)
public class HogeDaoImplTest {

    private DatabaseHelper databaseHelper;

    @Before
    public void setup() {
        databaseHelper = OpenHelperManager.getHelper(new Activity(), DatabaseHelper.class);
    }

    @After
    public void tearDown() {
        if (databaseHelper != null) {
            databaseHelper.clearAllTable();
            OpenHelperManager.releaseHelper();
            databaseHelper = null;
        }
    }

    @Test
    public void testFirst() throws Exception {
        HogeDao dao = databaseHelper.getDao(Hoge.class);
        Hoge hoge = new Hoge("fuga");
        dao.create(hoge);


        List<Hoge> list = dao.queryForAll();

        assertThat(list.size(), is(equalTo(1)));

    }

    @Test
    public void testSecond() throws Exception {
        HogeDao dao = databaseHelper.getDao(Hoge.class);
        Hoge hoge = new Hoge("fuga");
        dao.create(hoge);


        List<Hoge> list = dao.queryForAll();

        assertThat(list.size(), is(equalTo(1)));
    }
}

という感じで、テストは動くしパスする。

ShadowSQLiteOpenHelperはインメモリなDBをエミュレートしてくれるらしくて、接続を切ればデータは全部パーになる。ので@Beforeでこういうふうにしておくと、毎回DatabaseHelper::onCreateが走ってTableUtils.createTableIfNotExists(connectionSource, Hoge.class);されて、1つのテストが終わるとDBは吹っ飛ぶので Afterで毎回データを消しておけば、テストの順番がどうであれ同じ結果がでるべきだよね思想に沿った感じになる。なってると思う。
※同一テストクラス内ではデータはパーにならなかった。この辺もうちょっと調べないと。。。とにかく、全部のテスト回すときなんかは全部のテストが終わるまではDBは生き残っているので、各テストでちゃんとデータは消しとかなければ駄目だし、auto-generateなidを使う時も、割り振られるIDを予測したテスト(例えばデータを1件入れたらそのIDは1と推測したテスト)を書くといつかコケるので・・・。

まぁ、テーブルが複数あると毎回全部テーブル作られちゃうのがちょっとムダだけど。インメモリだから早いし、そもそも僕は4個くらいしかテーブルないからなんともない。


あとOpenHelperManager.getHelper(new Activity(), DatabaseHelper.class);のところでnew Activity()ってなんとなくやってるんだけど、これがあるべきなのかはよくわからない。引数として求められているから適当に充ててあるだけ。


こうやるべき、的なのがあったら教えてくださいん!