編輯:關於Android編程
面對android studio Run 一次項目要等好幾分鐘的痛點,不得不研究一下android studio 的單元測試。
其實我的目的很簡單,在不對視圖進行操作的前提下,測試一些activity 的生命周期,或網絡拉取數據的一些處理,比如解析 json 數據啊,做網絡請求啊等等,也就是對 Model層的測試。這些不需要操作視圖,但在沒有單元測試環境下,比如我們網絡請求一些數據,Log 打印看看是否請求成功,卻又要 利用模擬器或真機Run 一次項目,花費好幾分鐘,這是不能容忍的。
於是乎,強大的 android studio 也考慮到了這一點,給我們提供的簡單的單元測試類。
讓我們來簡單的了解學習一下吧。
首先先來了解一下一些名稱,方便下面介紹和使用:
在java中咱們有用過 JUnit 的 單元測試 ,那android 也是基於 java 語言編寫的,所以也有個 JUnit的單元測試。在做 android 的單元測試需要導入依賴:
androidTestCompile 'junit:junit:4.12'
testCompile 'junit:junit:4.12'
其中, test目錄為在本機執行單元測試代碼的目錄, androidTest為在Android設備上執行單元測試代碼的目錄。如下圖:
Android 自帶的 junit單元測試的一些測試類(androidTest測試 需要運行在模擬機或真機上)
1、InstrumentationTestCase框架:
Instrumentation和Activity有點類似,只不過Activity是需要一個界面的,而Instrumentation並不是這樣的,我們可以將它理解為一種沒有圖形界面的,具有啟動能力的,用於監控其他類(用Target Package聲明)的工具類。
舉個例子,利用InstrumentationTestCase 啟動一個activity:
在androidTest下新建一個java類,並且繼承自InstrumentationTestCase編寫一個public void的方法,但是必須要是方法名以test打頭,比如testPublishSubject,並不需要@Test注解
public class TestSubject extends InstrumentationTestCase { private static final String LOG_TAG = "test"; public void testPublishSubject() { launchActivity("demo.zts.com.demo",SecondActivity.class,null); } }
2、ApplicationTestCase——測試整個應用程序的類。它允許你注入一個模擬的Context到應用程序中,在應用程序啟動之前初始化測試參數,並在應用程序結束之後銷毀之前檢查應用程序。
使用Context,你可以浏覽資源,文件,數據庫等等。基類是AndroidTestCase,一般常見的是它的子類,和特定組件關聯。
測試代碼如下:
public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); String app_name = getResources().getString(R.string.app_name); Log.i("MyApp",".........MyApp....app_name.........."+app_name); } } public class ApplicationTest extends ApplicationTestCase<MyApp> { public ApplicationTest() { super(MyApp.class); } public void testStart() { String str = null; str = mContext.getResources().getString(R.string.app_name); Log.i("..",".............ApplicationTest ...........app_name............."+str); }
Log 日志:
07-22 23:27:10.276 32259-32259/demo.zts.com.demo I/MyApp: .........MyApp....app_name..........demo
07-22 23:27:10.276 32259-32319/demo.zts.com.demo I/TestRunner: started: testStart(demo.zts.com.demo.ApplicationTest)
07-22 23:27:10.286 32259-32319/demo.zts.com.demo I/..: .............ApplicationTest..........app_name..............demo
3、ActivityUnitTestCase——對單個Activity進行單一測試的類。使用它,你可以注入模擬的Context或Application,或者兩者。它用於對Activity進行單元測試。也就是說你可以用於測試單獨的activity ,雖然也需要利用模擬機或真機啟動,但你啟動的只是你需要做測試的activity,於其他activity無關。
測試代碼如下:
要測試的 activity
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); System.out.println("...............MainActivity......onCreate............"); Log.i("MainActivity","................onCreate............................"); } @Override protected void onStart() { super.onStart(); System.out.println("...............MainActivity......onStart............"); Log.i("MainActivity","................onStart............................"); } @Override protected void onStop() { super.onStop(); System.out.println("...............MainActivity......onStop............"); Log.i("MainActivity","................onStop............................"); } @Override protected void onDestroy() { super.onDestroy(); System.out.println("...............MainActivity......onDestroy............"); Log.i("MainActivity","................onDestroy............................"); } }
測試類
public class TestActivity extends ActivityInstrumentationTestCase2<MainActivity> { private Context ctx; public TestActivity() { super(MainActivity.class); } @Override protected void setUp() throws Exception { super.setUp(); ctx = getActivity().getApplicationContext(); } public void testStart() { Intent intent = new Intent(ctx, MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ctx.startActivity(intent); Log.i("TestActivity","................startActivity............................"); }
測試 Log 日志:
* 07-22 23:39:44.146 3171-3171/demo.zts.com.demo I/System.out: ...............MainActivity......onCreate............
07-22 23:39:44.146 3171-3171/demo.zts.com.demo I/MainActivity: ................onCreate............................
07-22 23:39:44.151 3171-3171/demo.zts.com.demo D/MZPerfObserver: demo.zts.com.demo onCreate consume 153 ms
07-22 23:39:44.151 3171-3171/demo.zts.com.demo I/System.out: ...............MainActivity......onStart............
07-22 23:39:44.151 3171-3171/demo.zts.com.demo I/MainActivity: ................onStart............................
07-22 23:39:44.326 3171-3171/demo.zts.com.demo D/OpenGLRenderer: Enabling debug mode 0
07-22 23:39:44.361 3171-3171/demo.zts.com.demo I/System.out: ...............MainActivity......onStop............
07-22 23:39:44.361 3171-3171/demo.zts.com.demo I/MainActivity: ................onStop............................
07-22 23:39:44.421 3171-3224/demo.zts.com.demo I/TestActivity: ................startActivity............................
還有很多常見的測試,比如ServiceTestCase,ProviderTestCase2等,大家需要慢慢琢磨。
Android 自帶的 junit單元測試的一些測試類(test 測試 ,不需要模擬機,電腦直接運行)
比如我需要測試一段java代碼,而這段java代碼跟android沒關系,也就是不用到android的資源,如context,activity 等,說白了就是簡單的 java 測試,當然,嘿嘿,android studio也是可以做java代碼測試的。
測試代碼如下,測試 4+4 等於幾:
public class ExampleUnitTest { @Test public void testAdd() { int i = 0; i = 4+4; System.out.print(".............. "+i); Log.i("TAG","..................."+i); // 比較 i 是否 等於 8 ,相等的話通過測試!!! Assert.assertEquals(8, i); } }
測試成功:
以上測試類的運行是 -點擊測試右鍵 - 選擇 RunXXXXX
/*********************華麗分割線***********************/
看了半天好像也沒有解決文章最初提到的一個痛點啊,就是我需要測試android的資源,但又不想運行笨重的模擬機或真機,怎麼辦呢? 媽蛋,被騙了,還錢 -_-、、、 確實,上面提到的測試方法雖然沒有解決拜托模擬機測試的痛點,但基於模擬機單元測試的 androidTest 確實方便我們做一些 單獨功能的測試,而且能做 UI 測試,因為需要模擬機或真機嘛,所以 UI 或視圖測試是沒問題的。 還有test 測試,可以做一些不需要android資源的 java代碼測試,也是在android開發當中很方便的,不用在啟用eclipse 做測試,直接android studio 既可以了。
忽悠,接著 忽悠 -_-////
其實要想脫離 模擬機或真機,又要做使用android資源的測試,如 使用Context,浏覽資源,文件,數據庫等等。 也是可以的!!! 那 就只有第三方測試框架了 Robolectric
666,你是來做宣傳的嗎 -_-、、、不過真的很好用,也能很好的解決咱們的痛點。
接下來利用個需求來講解 Robolectric 測試,免得我忽悠你們。
拿到 android 目錄下的 assets 下的json01.txt文件 是一段json數據,讓後進行解析,解析後將數據顯示。 分析:這個需求就跟android下的資源有關,而咱們利用 Robolectric 做單元測試,並且不需要模擬機或真機的支持。
其中json數據
{ "name": "coolxing", "age": 24, "male": true, "address": { "street": "huiLongGuan", "city": "beijing", "country": "china" } }
首先需要 Robolectric 依賴,在你的 app module 下注入依賴:
testCompile 'org.robolectric:robolectric:3.0'
注意是 testCompile 而不是 androidTestCompile ,不然你有需要啟動模擬器了。並且測試類也是 在 test 下的
測試類:
@RunWith(RobolectricGradleTestRunner.class) @Config(constants = BuildConfig.class, sdk = 21) public class MainActivityTest2 { @Test public void testJson(){ String str = null; str = RuntimeEnvironment.application.getResources().getString(R.string.app_name); AssetManager am = null; am = RuntimeEnvironment.application.getAssets(); String strData = null; try { InputStream inputStream = am.open("json01.txt"); byte buf[] = new byte[1024]; inputStream.read(buf); strData = new String(buf); strData =strData.trim(); strData.trim(); } catch (IOException e) { } jsonBean foo = new Gson().fromJson(strData, jsonBean.class); System.out.println("...............json.................."+foo.name); System.out.println("...............json.................."+foo.address); System.out.println("...............json.................."+foo.age); } }
測試結果:
看,咱們利用application 拿到 android 下的資源,但又不像剛才上面的 androidTestCompile 需要模擬機,是不是很6,我電腦配置比較低,本次測試需要40S多,但不真機快多了。
am = RuntimeEnvironment.application.getAssets();
需要注意幾點,類頭部需要聲明 @ 注解:
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
並且測試方法是以 textxxx() 開頭的,如上面的 testJson() ,方法也需要@Test注解!!!
Robolectric 還可以測試 activity ,如:
@RunWith(RobolectricGradleTestRunner.class) @Config(constants = BuildConfig.class, sdk = 21) public class MainActivityTest2 { @Test public void testMainActivity() { MainActivity mainActivity = Robolectric.setupActivity(MainActivity.class); mainActivity.findViewById(R.id.main_tv).performClick(); Intent expectedIntent = new Intent(mainActivity, SecondActivity.class); ShadowActivity openActivity = Shadows.shadowOf(mainActivity); Intent actualIntent = openActivity .getNextStartedActivity(); // Assert.assertEquals(expectedIntent, actualIntent); }
其中
MainActivity mainActivity = Robolectric.setupActivity(MainActivity.class);
這句代碼就是啟動了MainActivity 的生命周期
Robolectric 單元測試類 的 啟動 也是跟 上面test 測試類一樣,選擇 -MainActivityTest2 --右鍵 -- 選擇 Run MainActivityTest2
好了,單元測試就介紹到這裡,
其實我也只是初步理解,上面那些基本的也是我做項目的需要我才去學習使用的,還有好多強大的功能大家慢慢探索。
1.總結之前學習的關於屬性動畫的筆記 和 學習了郭霖大神的 屬性動畫高級用法相關的博客之後的記錄2.學習loading… 2.1補間動畫 PK 屬性動畫在篇
先看看效果圖:實現思路:擦除圖片相應的角,然後層疊圖片,產生傾斜效果代碼實現:1、定義屬性在values文件夾下的attrs文件添加以下代碼<resources&g
版本:1.0日期:2014.5.17 2014.6.1版權:© 2014 kince 轉載注明出處 在介紹SwitchButton之前,先來看一下系統Butt
AsyncTask的介紹及基本使用方法關於AsyncTask的介紹和基本使用方法可以參考官方文檔和《Android開發筆記之:深入理解多線程AsyncTask》這裡就不重