前言
上篇《Android单元测试 - 几个重要问题》 讲解了“何解决Android依赖、隔离Native方法、静态方法、RxJava异步转同步”这几个Presenter单元测试中常见问题。如果读者你消化得差不多,就接着看本篇吧。
在日常开发中,数据储存是必不可少的。例如,网络请求到数据,先存本地,下次打开页面,先从本地读取数据显示,再从服务器请求新数据。既然如此重要,对这块代码进行测试,也成为单元测试的重中之重了。
笔者在学会单元测试前,也像大多数人一样,写好了sql代码,运行app,报错了....检查代码,修改,再运行app....这真是效率太低了。有了单元测试做武器后,我写DAO代码轻松了不少,不担心出错,效率也高。
常用的数据储存有:sqlite、SharedPreference、Assets、文件。由于这前三种储取数据方式,都必须依赖android环境,因此要进行单元测试,不能仅仅用junit & mockito了,需要另外的单元测试框架。接下来,笔者介绍如何使用robolectric进行DAO单元测试。
缩写解释:DAO (Data Access Object) 数据访问对象
Robolectric配置
Robolectric官网:http://robolectric.org/
Robolectric配置很简单的。
build.gradle :
- dependencies {
- testCompile "org.robolectric:robolectric:3.1.2"
- }
然后在测试用例XXTest加上注解:
- @RunWith(RobolectricTestRunner.class)
- @Config(constants = BuildConfig.class)
- public class XXTest {
- }
配置代码是写完了。
不过,别以为这样就完了。Robolectric最麻烦就是下载依赖! 由于我们生活在天朝,下载国外的依赖很慢,效果也一般,可能是https://oss.sonatype.org 服务器比较慢。
笔者已经下载好了依赖包,读者们可以到 http://git.oschina.net/kkmike999/Robolectric-Dependencies 下载robolectric 3.1.2的依赖包,按照Readme.md说明操作。
Sqlite
DbHelper:
- public class DbHelper extends SQLiteOpenHelper {
- private static final int DB_VERSION = 1;
- public DbHelper(Context context, String dbName) {
- super(context, dbName, null, DB_VERSION);
- }
- ...
- }
Bean:
- public class Bean {
- int id;
- String name = "";
- public Bean(int id, String name) {
- this.id = id;
- this.name = name;
- }
- }
Bean数据操作类 BeanDAO:
- public class BeanDAO {
- static boolean isTableExist;
- SQLiteDatabase db;
- public BeanDAO() {
- this.db = new DbHelper(App.getContext(), "Bean").getWritableDatabase();
- }
- /**
- * 插入Bean
- */
- public void insert(Bean bean) {
- checkTable();
- ContentValues values = new ContentValues();
- values.put("id", bean.getId());
- values.put("name", bean.getName());
- db.insert("Bean", "", values);
- }
- /**
- * 获取对应id的Bean
- */
- public Bean get(int id) {
- checkTable();
- Cursor cursor = null;
- try {
- cursor = db.rawQuery("SELECT * FROM Bean", null);
- if (cursor != null && cursor.moveToNext()) {
- String name = cursor.getString(cursor.getColumnIndex("name"));
- return new Bean(id, name);
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- cursor = null;
- }
- return null;
- }
- /**
- * 检查表是否存在,不存在则创建表
- */
- private void checkTable() {
- if (!isTableExist()) {
- db.execSQL("CREATE TABLE IF NOT EXISTS Bean ( id INTEGER PRIMARY KEY, name )");
- }
- }
- private boolean isTableExist() {
- if (isTableExist) {
- return true; // 上次操作已确定表已存在于数据库,直接返回true
- }
- Cursor cursor = null;
- try {
- String sql = "SELECT COUNT(*) AS c FROM sqlite_master WHERE type ='table' AND name ='Bean' ";
- cursor = db.rawQuery(sql, null);
- if (cursor != null && cursor.moveToNext()) {
- int count = cursor.getInt(0);
- if (count > 0) {
- isTableExist = true; // 记录Table已创建,下次执行isTableExist()时,直接返回true
- return true;
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- cursor = null;
- }
- return false;
- }
- }
以上是你在项目中用到的类,当然数据库一般开发者都会用第三方库,例如:greenDAO、ormlite、dbflow、afinal、xutils....这里考虑到代码演示规范性、通用性,就直接用android提供的SQLiteDatabase。
大家注意到BeanDAO的构造函数:
>>>>阅读全文