robolectric的最大特別是運行測試程序時不需要設(shè)備或者模擬器凉泄,在電腦中進行就可以了,自然測試程序的運行效率可以大大提升劳较。
環(huán)境搭建
gradle
gradle 中加入
dependencies {
...
testCompile 'junit:junit:4.10'
testCompile 'org.robolectric:robolectric:3.0'
}
==注意==
- 若寫成
testCompile
,則測試代碼放在 test 文件夾中 - 若寫成
androidTest
浩聋,則測試代碼放在 androidTest 文件夾中
Android studio 配置
切換成 Unit Tests
在Build Variants窗口內(nèi)的Test Artifact中選擇了"Unit Tests"
Linux 和 Mac 用戶需要進行這一步設(shè)置观蜗、
Run -> Edit Configurations -> Defaults -> Junit
注意Robolectric目前不支持android 5.1 API level 22,編譯時 sdk = 21 或者以下衣洁。
在project視圖中墓捻,test 文件夾下,有個綠的的java 文件夾坊夫,綠色文件夾表示是單元測試工程砖第。這些代碼能夠檢測目標(biāo)代碼的正確性,打包時單元測試的代碼不會被編譯進入APK中
Activity
Activity的創(chuàng)建
Activity activity = Robolectric.buildActivity(MyAwesomeActivity.class).create().get();
會創(chuàng)建一個MyAwesomeActivity
實例践樱,然后調(diào)用它的onCreat()方法
如果只想驗證其onResume()方法厂画,可以如下
ActivityController controller = Robolectric.buildActivity(MyAwesomeActivity.class).create().start();
Activity activity = controller.get();
// assert that something hasn't happened
activityController.resume();
// assert it happened!
如果想測試整個activity 的生命周期可以
Activity activity = Robolectric.buildActivity(MyAwesomeActivity.class).create().start().resume().visible().get();
等你需要在activity中,對view進行一些操作時候拷邢,比如
Robolectric.clickOn()
袱院,這時候你需要在create()
后加入visible()
舉例
我在工程中建立了三個Activity分別為 MainActivity,AnotherActivity,ThridActivity
在MainActivity加入按鍵跳轉(zhuǎn)到AnotherActivity中忽洛,
public void startAnotherActivity(View view) {
startActivity(new Intent(MainActivity.this, AnotherActivity.class));
}
增加單元測試用例判斷跳轉(zhuǎn)的是否正確
@Test
public void clickingLogin_shouldStartLoginActivity() {
Button button = (Button) activity.findViewById(R.id.button);
assertTrue(button.isEnabled());
button.performClick();
Intent expectedIntent = new Intent(activity, ThridActivity.class);
assertEquals(expectedIntent,shadowOf(activity).getNextStartedActivity() );
}
1.通過 activity.findViewById 找到button
2.判斷button是否可以點擊
3.點擊button
4.構(gòu)造一個intent(從MainActivity跳轉(zhuǎn)到ThridActivity)
5.判斷實際跳轉(zhuǎn)的和構(gòu)造的是否一致
結(jié)構(gòu)不一致報錯
java.lang.AssertionError:
Expected :Intent{componentName=ComponentInfo{io.github.xuyushi.robolectric/io.github.xuyushi.robolectric.ThridActivity}, extras=Bundle[{}]}
Actual :Intent{componentName=ComponentInfo{io.github.xuyushi.robolectric/io.github.xuyushi.robolectric.AnotherActivity}, extras=Bundle[{}]}
<Click to see difference>
at org.junit.Assert.fail(Assert.java:91)
at org.junit.Assert.failNotEquals(Assert.java:645)
at org.junit.Assert.assertEquals(Assert.java:126)
at org.junit.Assert.assertEquals(Assert.java:145)
可以很清楚的定位到錯誤
Dialog驗證
@Test
public void testDialog(){
Dialog dialog = ShadowDialog.getLatestDialog();
assertNotNull(dialog);
}
Toast驗證
@Test
public void testToast(){
assertEquals(toastContent, ShadowToast.getTextOfLatestToast());
}
Fragment的測試
如果使用support的Fragment腻惠,需添加以下依賴
testCompile "org.robolectric:shadows-support-v4:3.0"
shadow-support包提供了將Fragment主動添加到Activity中的方法:SupportFragmentTestUtil.startFragment(),簡易的測試代碼如下
@Test
public void testFragment(){
SampleFragment sampleFragment = new SampleFragment();
//此api可以主動添加Fragment到Activity中,因此會觸發(fā)Fragment的onCreateView()
SupportFragmentTestUtil.startFragment(sampleFragment);
assertNotNull(sampleFragment.getView());
}
訪問資源文件@Test
public void testResources() {
Application application = RuntimeEnvironment.application;
String appName = application.getString(R.string.app_name);
String activityTitle = application.getString(R.string.title_activity_simple);
assertEquals("test", appName);
assertEquals("testActivity",activityTitle);
}
Shodaw
Robolectric的本質(zhì)是在Java運行環(huán)境下欲虚,采用Shadow的方式對Android中的組件進行模擬測試集灌,從而實現(xiàn)Android單元測試。對于一些Robolectirc暫不支持的組件复哆,可以采用自定義Shadow的方式擴展Robolectric的功能欣喧。
定義原始類
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
定義 shardow 類
@Implements(User.class)
public class ShadowUser {
@Implementation
public String getUsername() {
return "from ShadowUser";
}
}
需要讓系統(tǒng)知道 ShardowUser 的存在
定義自己的 RobolectricGradleTestRunner
類,繼承自RobolectricGradleTestRunner
public class UserShadowTestRunner extends RobolectricGradleTestRunner {
public UserShadowTestRunner(Class<?> klass) throws InitializationError {
super(klass);
}
@Override
public InstrumentationConfiguration createClassLoaderConfig() {
InstrumentationConfiguration.Builder builder = InstrumentationConfiguration.newBuilder();
/**
* 添加要進行Shadow的對象
*/
builder.addInstrumentedClass(User.class.getName());
return builder.build();
}
}
test 測試中使用
Runwith 使用上面自定義的類
同時指明使用 ShadowUser.class
梯找,多個類可以加{},中間使用,
分開
@RunWith(UserShadowTestRunner.class)
@Config(constants = BuildConfig.class, shadows = ShadowUser.class)
public class LoginActivityTest {
@Test
public void testCase() {
User user = new User("username", "password");
assertEquals("from ShadowUser", user.getUsername());
}
}
網(wǎng)絡(luò)請求 mock
gradle 中加入
testCompile 'org.robolectric:shadows-httpclient:3.0'
testCompile 'org.robolectric:robolectric-shadows:3.0'
更多robolectric 包見
http://mvnrepository.com/artifact/org.robolectric
未搞定的
- 項目網(wǎng)絡(luò)請求使用的是 volley 唆阿,網(wǎng)絡(luò)請求并沒有找到合適辦法模擬
- 使用了第三方框架 butterknief,并不能模擬
以上有知道如何解決的 請告訴我一聲~ xmy166@gmil.com
參考
http://hkliya.gitbooks.io/unit-test-android-with-robolectric/content/2-api-explained.html
http://www.reibang.com/p/9d988a2f8ff7
http://robolectric.org
http://chriszou.com/android-unit-testing-with-robolectric