Android单元测试 - Sqlite、SharedPreference、Assets、文件操作 怎么测?

前言

上篇《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 :

  1. dependencies { 
  2.     testCompile "org.robolectric:robolectric:3.1.2" 
  3.  

然后在测试用例XXTest加上注解:

  1. @RunWith(RobolectricTestRunner.class) 
  2. @Config(constants = BuildConfig.class) 
  3. public class XXTest { 
  4.  

配置代码是写完了。

不过,别以为这样就完了。Robolectric最麻烦就是下载依赖! 由于我们生活在天朝,下载国外的依赖很慢,效果也一般,可能是https://oss.sonatype.org 服务器比较慢。

笔者已经下载好了依赖包,读者们可以到 http://git.oschina.net/kkmike999/Robolectric-Dependencies 下载robolectric 3.1.2的依赖包,按照Readme.md说明操作。

Sqlite

DbHelper:

  1. public class DbHelper extends SQLiteOpenHelper { 
  2.  
  3.     private static final int DB_VERSION = 1; 
  4.  
  5.     public DbHelper(Context context, String dbName) { 
  6.         super(context, dbName, null, DB_VERSION); 
  7.     } 
  8.     ... 
  9.  

Bean:

  1. public class Bean { 
  2.     int id; 
  3.     String name = ""
  4.  
  5.     public Bean(int id, String name) { 
  6.         this.id = id; 
  7.         this.name = name
  8.     } 
  9.  

Bean数据操作类 BeanDAO:

  1. public class BeanDAO { 
  2.     static boolean isTableExist; 
  3.      
  4.     SQLiteDatabase db; 
  5.  
  6.     public BeanDAO() { 
  7.         this.db = new DbHelper(App.getContext(), "Bean").getWritableDatabase(); 
  8.     } 
  9.  
  10.     /** 
  11.      * 插入Bean 
  12.      */ 
  13.     public void insert(Bean bean) { 
  14.         checkTable(); 
  15.  
  16.         ContentValues values = new ContentValues(); 
  17.         values.put("id", bean.getId()); 
  18.         values.put("name", bean.getName()); 
  19.  
  20.         db.insert("Bean"""values); 
  21.     } 
  22.  
  23.     /** 
  24.      * 获取对应id的Bean 
  25.      */ 
  26.     public Bean get(int id) { 
  27.         checkTable(); 
  28.  
  29.         Cursor cursor = null
  30.  
  31.         try { 
  32.             cursor = db.rawQuery("SELECT * FROM Bean"null); 
  33.  
  34.             if (cursor != null && cursor.moveToNext()) { 
  35.                 String name = cursor.getString(cursor.getColumnIndex("name")); 
  36.  
  37.                 return new Bean(id, name); 
  38.             } 
  39.         } catch (Exception e) { 
  40.             e.printStackTrace(); 
  41.         } finally { 
  42.             if (cursor != null) { 
  43.                 cursor.close(); 
  44.             } 
  45.             cursor = null
  46.         } 
  47.         return null
  48.     } 
  49.      
  50.     /** 
  51.      * 检查表是否存在,不存在则创建表 
  52.      */ 
  53.     private void checkTable() { 
  54.         if (!isTableExist()) { 
  55.             db.execSQL("CREATE TABLE IF NOT EXISTS Bean ( id INTEGER PRIMARY KEY, name )"); 
  56.         } 
  57.     } 
  58.  
  59.     private boolean isTableExist() { 
  60.         if (isTableExist) { 
  61.             return true; // 上次操作已确定表已存在于数据库,直接返回true 
  62.         } 
  63.          
  64.         Cursor cursor = null
  65.         try { 
  66.             String sql = "SELECT COUNT(*) AS c FROM sqlite_master WHERE type ='table' AND name ='Bean' "
  67.  
  68.             cursor = db.rawQuery(sql, null); 
  69.             if (cursor != null && cursor.moveToNext()) { 
  70.                 int count = cursor.getInt(0); 
  71.                 if (count > 0) { 
  72.                     isTableExist = true; // 记录Table已创建,下次执行isTableExist()时,直接返回true 
  73.                     return true
  74.                 } 
  75.             } 
  76.         } catch (Exception e) { 
  77.             e.printStackTrace(); 
  78.         } finally { 
  79.             if (cursor != null) { 
  80.                 cursor.close(); 
  81.             } 
  82.             cursor = null
  83.         } 
  84.         return false
  85.     } 
  86.  

以上是你在项目中用到的类,当然数据库一般开发者都会用第三方库,例如:greenDAO、ormlite、dbflow、afinal、xutils....这里考虑到代码演示规范性、通用性,就直接用android提供的SQLiteDatabase。

大家注意到BeanDAO的构造函数:

>>>>阅读全文
展开阅读全文

没有更多推荐了,返回首页