Robolectric测试框架使用文档
?
Robolectric使用文檔
--keeng2008@qq.com 2016-01-07
1.測試驅動你的Android應用代碼
在Android模擬器或者手機上運行單元測試是很漫長的。每次編譯、部署、啟動應用都需要耗時1分鐘以上。有沒有更好的辦法呢?
Robolectric 是一個針對于Android SDK 的單元測試框架,使用它可以測試驅動你的Android應用程序的開發。測試用例只需要在JVM基礎上就能運行起來,這節省了大量的時間。使用Robolectric后,你只需要寫出類似這樣的測試代碼:
| @RunWith(RobolectricTestRunner.class) public class MyActivityTest { ? @Test ? public void clickingButton_shouldChangeResultsViewTest() throws Excepiton { MyActivity activity = Robolectric.setupActivity(MyActivity.class); ? Button button = (Button) activity.findViewById(R.id.button); TextView results = (TextView) activity.findViewById(R.id.results); ? ?button.performClick(); ?assertThat(results.getText().toString()).isEqualTo("Robolectric Rocks!"); } } ? |
?
Robolectric 通過重寫Android SDK 的實現類,然后被加載到測試工程中,然后讓上面的測試代碼可以在JVM上運行。
?
SDK,資源,原生方法的模擬
Robolectric 模擬了界面生成,資源加載,還有大量的基于Android設備底層C語言提供的原生方法提供的功能。這可以讓測試模擬到跟真實設備一樣的大部分事情。如果對于一些具體的SDK方法提供自己的實現,也是非常容易的,所以你可以模擬真實機器上發生的一些出錯的條件,出錯的行為。
?
2.開始使用Robolectric
Robolectric在Gradle和Maven上測試運行得很好。
使用Gradle
在build.gradle里添加下面一行:
| testCompile “org.robolectric:robolectric:3.0” |
在測試用例代碼中添加Gradle Test的注解
| @RunWith(RobolectricGradleTestRunner.class) @Config(constants = BuildConfig.class) public class SandwichTest { } |
?
注意,一定要配置constants屬性指向BuildConfig.class, 編譯系統會自動生成這個類,不用手動創建。Robolectric讀取constants配置好的輸出路徑,Gradle生成項目時會使用到。如果沒有這些值,Robolectric就找不到應用的manifest, resources還有assets等資源。
在Android Studio 生成
Robolectric支持Android Studio 1.1.0及更高的版本。只需要簡單的參照上面Gradle的配置。然后在”Build Variants”選項中下拉選擇Unit Tests就可以運行了。
在Gradle的Task列表中選擇testDebug運行(第一次運行需要的時間很久)。
?
?
3.編寫第一個例子
創建一個Activity,顯示一個登陸界面。
| <?xml version="1.0" encoding="utf-8"?> <LinearLayout ??? xmlns:android="http://schemas.android.com/apk/res/android" ??? android:layout_width="match_parent" ??? android:layout_height="match_parent"> ? ??? <Button ??????? android:id="@+id/login" ??????? android:text="Login" ??????? android:layout_width="wrap_content" ??????? android:layout_height="wrap_content"/> ? </LinearLayout> ? |
?
當用戶點擊登陸按鈕就跳轉到歡迎界面
| public class WelcomeActivity extends Activity { ? ??? @Override ??? protected void onCreate(Bundle savedInstanceState) { ??????? super.onCreate(savedInstanceState); ??????? setContentView(R.layout.welcome_activity); ? ??????? final View button = findViewById(R.id.login); ??????? button.setOnClickListener(new View.OnClickListener() { ??????????? @Override ??????????? public void onClick(View view) { ??????????????? startActivity(new Intent(WelcomeActivity.this, LoginActivity.class)); ??????????? } ??????? }); ??? } } ? |
?
我們希望測試的是,當用戶點擊登陸按鈕后,我們啟動了正常的intent。由于Robolectric只是一個模擬的單元測試框架,LoginActivity并不會真正的啟動,但是我們可以檢查是否準確的發出了WelcomActivity的intent。
| @RunWith(RobolectricTestRunner.class) public class WelcomeActivityTest { ? ??? @Test ??? public void clickingLogin_shouldStartLoginActivity() { ??????? WelcomeActivity activity = Robolectric.setupActivity(WelcomeActivity.class); ??????? activity.findViewById(R.id.login).performClick(); ? ??????? Intent expectedIntent = new Intent(activity, WelcomeActivity.class); ??????? assertThat(Shadows.shadowOf(activity).getNextStartedActivity()).isEqualTo(expectedIntent); ??? } } ? |
?
4.配置Robolectric
有幾種方法來配置Robolectric的運行時行為。
Config注解
最簡單的配置Robolectric的方法就是使用@Config注解。這個注解可以作用于類和方法,如果在類和方法都同時配置了同一個屬性,方法的配置會覆蓋類的配置。
基類的注解對于所有的子類都是有效的,所以如果你要在很多的類使用同一個配置,可以創建一個基類,然后把@Config注解移到基類中。
下面的例子展示了更多的配置內容。
配置SDK版本
Robolectric會使用你在manifest中指定的targetSdkVersion版本來運行測試代碼。如果你想測試在其它指定版本的表現,可以通過下面的修改這個SDK版本:
| @Config(sdk = Build.VERSION_CODES.JELLY_BEAN) public classSandwichTest { ? @Config(sdk = Build.VERSION_CODES.KITKAT) ? public void getSandwich_shouldReturnHamSandwich() { ? } } |
?
配置Application類
Robolectric會根據manifest的配置自動幫你創建一個Application類,如果你希望提供一個自己實現的類,可以這樣設置:
| @Config(application = CustomApplication.class) public class SandwichTest { ? ??? @Config(application = CustomApplicationOverride.class) ??? public void getSandwich_shouldReturnHamSandwich() { ??? } } |
?
配置Resource路徑
Robolectric為Gradle和Maven提供了默認的設置,但是也允許你修改這些資源的路徑,包括manifest, resource目錄,assets目錄。如果你有一個自定義的生成腳本這會非常有用。示例:
| @Config(manifest = "some/build/path/AndroidManifest.xml") public class SandwichTest { ? ??? @Config(manifest = "other/build/path/AndroidManifest.xml") ??? public void getSandwich_shouldReturnHamSandwich() { ??? } } |
默認的,Robolectric會假定你的resouces和assets都是放在目錄res和assets中。這些目錄都是配置成相對于manifest的相對目錄。你也可以在@Config注解中添加resourcesDir和assetsDir選項來修改資源路徑。
使用屬性配置文件
任何在@Config注解可以配置的屬性也可以寫成一個全局的properties文件。創建一個文件robolectric.properties,確認在classpath中可以找到。例如:
| sdk=18 manifest=some/build/path/AndroidManifest.xml shadows=my.package.ShadowFoo,my.package.ShadowBar |
?
系統屬性
還有以下的選項可以在properties中配置
robolectric.offline設置true后為離線狀態,不會在運行時去下載jar文件
robolectric.dependency.idr在離線狀態,提供一個運行時查找依賴文件的目錄
robolectric.logging.enable設為true后打開debug日志
?
5.控制Activity的生命周期
在Robolectric 2.2版本以前,創建Activity多數都是直接調用構造函數(new MyActivity())然后手動調用生命周期的函數如onCreate()。還有廣泛使用的ShadowActivity(例如ShadowActivity.callOnCreate()),這就是現在ActivityController的設計原型。
為了解決調用的混亂,Robolectric API提供了ActivityController,用它來簡化創建Activity還有控制Activity的生命周期。
不需要調用onCreate這些函數,ActivityController確保了Activity生命周期的一致性,這包括把Activity顯示到Window,還提供了如LayoutInflater這些系統服務。
具體怎么做
你不要直接new一個ActivityController,使用Robolectric.buildActivity()來獲得一個實例。對于大多數基本的測試用命 ,你只需要一行代碼就能初始化一個Activity:
| Activity activity = Robolectric.buildActivity(MyAwesomeActivity.class).create().get(); |
這會創建一個MyAwesomeActivity,并且已經調用了onCreate()。
想去檢查一些在onCreate()和onResume()之間發生的事件,這很簡單:
| ActivityController controller = Robolectric.buildActivity(MyAwesomeActivity.class).create().start(); Activity activity = controller.get(); // assert that something hasn't happened activityController.resume(); // assert it happened! |
還有類似的函數包括start(), pause(), stop()和destroy()。所以如果你想測試一個完整的創建周期:
| Activity activity = Robolectric.buildActivity(MyAwesomeActivity.class).create().start().resume().visible().get(); |
模擬使用intent來啟動一個Activity:
| Intent intent = new Intent(Intent.ACTION_VIEW); Activity activity = Robolectric.buildActivity(MyAwesomeActivity.class).withIntent(intent).create().get(); |
還有保存狀態等調用:
| Bundle savedInstanceState = new Bundle(); Activity activity = Robolectric.buildActivity(MyAwesomeActivity.class) ??? .create() ??? .restoreInstanceState(savedInstanceState) ??? .get(); |
需要更多關于ActivityController的功能可以查看Java Doc文檔。
?
奇怪!調用visible() 有用嗎?
實際上一個Android app, 一個Activity的視圖會在onCreate()被調用后一段時間才添加到Window上的,在此之前,Activity的控件是不可見的,這意味著你沒法處理任何的點擊交互。Activity的控件樹在onPostResume()被調用后才添加到設備或者模擬器的Window上。與其在猜測不確定的時候點Activity會被顯示,Robolectric給單元測試的開發者提供了直接控制Activity顯示的功能。
然而我們什么時候調用它呢?就是當你在Activity內部需要操作控件的交互時,調用類似于Robolectric.clickOn()需要視圖是可見的。注意調用順序是先onCreate()再調用visible()。
6.使用額外的子模塊
為了減少測試時需要依賴的數量,Robolectric對Android的模擬也拆分為很多附加的子模塊,只有在Android SDK的基本包里面的類才包含在Robolectric的主模塊中。其它的如appcompat或者support 依賴庫是作為附加子模擬提供的。下面的表格中列出了可用的附加包:
| SDK包 | Robolectric附加包 |
| com.android.support.support-v4 | org.robolectric:shadows-support-v4 |
| com.android.support.multidex | org.robolectric:shadows-multidex |
| com.google.android.gms:play-services | org.robolectric:shadows-play-services |
| com.google.android.maps:maps | org.robolectric:shadows-maps |
| org.apache.httpcomponents:httpclient | org.robolectric:shadows-httpclient |
注意附加包的功能需要在build.gradle或者pom.xml里添加后才能使用。
?
?
參考:http://robolectric.org/getting-started/
?
?
?
?
?
?
?
?
總結
以上是生活随笔為你收集整理的Robolectric测试框架使用文档的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 抽取数据shell
- 下一篇: Flutter实现帧动画