Robolectric使用(三)驱动activity生命周期

在Robolectric2.2之前,大多数测试通过调用构造方法来直接创建activites(new MyActivity()),然后手工调用生命周期方法比如onCreate()。一些shadowActivity的方法也被广泛的应用(shadowActivity.callOnCreate())。


Robolectric的一个流式API ActivityController改变了这些糟糕的情况,它通过模拟android如何创建activity和通过他们的生命周期驱动来工作。ActivityController是一个在2.0推出但是现在需要在2.2使用的流式API。除了调用像onCreate()之外的方法,它确保activity的内部状态和生命周期是相符的。

What do I do now?

我们通常不会直接创建一个ActivityController,使用Robolectric.buildActivity()来得到。在你只是简单的需要一个初始化好的activity的最基本的测试中,你通常可以通过下面的方式来得到:

Activity activity=Robolectric.buildActivity(MyActivity.class).create().get();

这将会创建一个MyActivity的新对象,并且通过生命周期调用它的onCreate()方法。
想要验证在onResume()的时候发生的事情是在onCreate()之后没有发生的?可以用如下方法:

ActivityController controller = Robolectric.buildActivity(MyActivity.class).create().start();
Activity activity =controller.get();
//assert that something hasnt happend
activityController.resume();
//assert it happend!

类似的方法包括start(),pause(),stop(),destroy()。如果你想要测试完整的创建生命周期可以用下面的代码:

Activity activity = Robolectric.buildActivity(MyActivity.class).create().start().resume.visible().get();

你可以通过intent模拟启动一个activity

Intent intent = new Intent(Intent.ACTION_VIEW);
Activity activity = Robolectric.buildActivity(MyActivity.class).withIntent(intent).create().get();

或者恢复savedInstanceState

Bundle savedInstanceState=new Bundle();
Activity activity = Robolectric.buildActivity(MyActivity.class).create().restoreInstanceState(savedInstanceState).get();

如果测试中需要更多的方法,可以参考AcivityController的Java Docs

在上面的使用中有一个visible()方法,这个方法的意义是什么?
在真实的android app中,activity的view层是没有附着到window上的直到onCreate()被调用之后,在这些发生之前,activity的view不会被置为visible,这就意味着不能点击他们,在真机或者模拟器上activity的onPostResume()被调用之后才会附着到window上。
所以什么时候去调用visible()?当你需要在activity进行交互的时候,比如Robolectric.clickOn()方法需要view是visible状态并且功能完备,这种情况就需要在create()之后调用visible().



使用扩展模块

为了减少将要测试的应用的外部依赖数量,robolectric的shadows被分割成许多扩展包,Robolectric主模块仅仅提供了为基础androidsdk提供的shadows,对appcompat或者support library在扩展模块中提供,如下表所示:

SDK Package Robolectric Add-On package
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


Using Library Resources

当Robolectric运行一个test的时候,它试图去下载并且索引应用所有的资源,所以当调用assetManager的时候可以返回这些资源。对于三方库提供的资源,一些扩展性配置就是需要的。

Using Libraries with Gradle

如果你使用gradle构建你的项目,并且使用 ==RobolectricTestRunner== 来运行你的test,不需要额外的配置,这是因为android的gradle插件将会在构建的时候merge三方库资源和项目的资源文件。RobolectricGradleTestRunner在version3.1过期了。

UsingLibraries with Maven

如果你使用maven来构建项目,你将需要告诉Robolectric哪里的unpacked 资源是为你使用的哪一个库准备的,这个配置可以指定在@Config注解里:

@RunWith(RobolectricTestRunner.class)
@Config(libraries={
    "build/unpacked-libraries/library1",
    "build/unpacked-libraries/library2"
})
public class TestClass{
    
}

或者在robolectric.properties文件中指定:

libraries=build/unpacked-libraries/library1,build/unpacked-libraries/library2

所有路径相对于工程的根目录

Debugging Resource Loading Issues

如果你不能确信一个指定的库的资源是否已经下载完成,通过设置系统属性==robolectric.logging.enabled=true== 来打开debug日志然后再运行测试。你会看到一些输出如下:

loading resources for 'com.foo' from build/unpacked-libraries/library1...

如果你看不到一个指定的库在这个列表中,再次检查一下配置



Using Qualified Resources(限定资源)

android developer docs 的描述中,资源限定符允许你根据设备的语言,屏幕尺寸,是否夜间等因素改变你的资源加载。当你要做出严谨的测试是乏味的(每个字符串都有所有支持的语言的翻译),你会发现你想要在不同的限定环境来运行测试。

Specifying Resources in Test

指定一个资源限定符很简单,通过在你的测试用例上或者测试类上使用@Config注解简单的添加想要的限定符,这取决于你是想要改变你整个文件还是单个测试的的资源限制。
给出如下资源values/strings.xml

<string name="not_overridden">Not Overridden</string>
<string name="overridden">Unqualified value</string>
<string name="overridden_twice">Unqualified value</string>

value-en/strings.xml

<string name="overridden">English qualified value</string>
<string name="overridden_twice">English qualified value</string>

values-en-port/strings.xml

<string name="overridden_twice">English portrait value</string>

下面使用android资源限定规则的Robolectric测试将会通过

@Test
@Config(qualifiers="en-port")
public void shouldUseEnglishAndPortraitResources(){
    final Context context = RuntimeEnvironment.application;
    assertThat(context.getString(R.id.not_overridden)).isEqualTo("Not Overridden");
    assertThat(context.getString(R.id.overridden)).isEqualTo("English     qualified value");
    assertThat(context.getString(R.id.overridden_twice)).isEqualTo("English portrait qualified value");
}

多种限定符需要用破折号分割开,在google限定符列表里可以找到对应的限定符

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容