robolectric使得可以在jvm中运行android代码。
Question 1
一般而言,在使用robolectric对activity中的方法进行测试的时候,需要先setup出一个activity对象,然后来调用这个activity对象的方法,或者通过这个activity对象去findViewById一个View,然后performClick,模拟点击这个view。
Robolectric.setupActivity(RoboActivity.class);
文档中并没有任何注释。大概猜测这个方法在执行后,会走activity生命周期的onCreate,onResume等方法,并将context传入。(大概类似手机点击打开了这个界面)那么,问题来了,在执行其生命周期方法时,大量的外部依赖如何解决。
前提:由于Application里面有不少加载so库,初始化等的方法,故使用
@Config(constants= BuildConfig.class,sdk=21,application= RoboApplication.class)自己定义一个空的BaseApplication来代替。
在执行onCreate方法时,大多android相关的代码可以正常执行,但一旦涉及到application的,比如mSpu=newSharedPreferencesUtil(UIUtils.getContext());
UIUtils.getContext()的操作需要去获得一个application 的context,由于Robolectric模拟的是RoboApplication的启动,并没有去启动app自身的application,因此这个context获取的是null。导致后续关于sharedPreference的所有操作无法执行。
如果RoboActivity是一个普通对象,那么可以通过依赖注入,把sharedPreference通过构造函数传入,在传入时,把sharedPreference 进行mock就行了。(这就是所谓的隔离了sharedPreference这个依赖?)但这是activity,如何隔离这个依赖?
隔离不了这些依赖,是否对于这样一个 上千行的activity,就无法对其进行测试了?
Question 2
//用于robolectric进行测试的方法,待修改为正常方法 //FIXME: 17/8/11
public voidsetLayoutParamsTest(RelativeLayout rl_college_list_img) {
rl_college_list_img.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,UIUtils.getScreenWidth((Activity)mContext)/2));
}
某日需求变更,需要将列表展示的图片高度调整为屏幕宽度的一半,于是在Adapter里面写了上面这个方法,结果运行后崩溃。发现rl_college_list_img处在LinerLayout中,因此会有LayoutParams cast Exception。这一过程经历了运行,然后再手动点击到修改页面,才发现问题。心血来潮,如果用单元测试是否可以不用这么麻烦,直接单测,十几秒内就发现问题呢。于是对Adapter进行测试,并创建上面的方法。Run ~
竟然通过了。
有点崩溃。debug发现 好像真的就只执行了这个方法中的一部分
requestLayout();的执行似乎没有效果(debug得不仔细,只是推测),因此并没有上层父布局Linerlayout的onMeasure操作,而这个异常就是由onMeasure调用measureVertical后抛出的。
心态崩了... 这也测不出来,要你何用。
所以到底如何能够让大多数方法可测呢?就像小创说的效果:
”节约时间:对于安卓开发来说,一遍一遍的运行app,再执行相应的用户操作,看界面是否显示正确的结果,通过这种方式来测试自己的新代码、重构是否是正确的,这是非常浪费时间的一件事情,而且效果还不好。有了单元测试,我现在开发过程中几乎已经不用把app运行起来了,速度相对来说快多了。“http://www.jianshu.com/p/68212278f592
感觉完全办不到啊,任何一个ui上的改动,都似乎要运行起手机。
后期再看看有没有使用空间,不然真的要弃坑了...
8.15更新:
Advantage1:
吸收大神的经验,尽量用隔离android代码与java代码,然后用junit4对java进行测试。今天抽出一个model层,将异步网络请求request类放入这层。 model层应该是不会含有任何android 代码的,ok,写好
run~。 fail了。'java.lang.RuntimeException: Method isEmpty in android.text.TextUtils not mocked'错误。 ok,doRequest里面用到了 android的TextUtils类。
http://www.jianshu.com/p/f5d197a4d83a,根据键盘男 的这个经验...在test/java目录下,创建android.text.TextUtils类.
继续run~fail again
好吧,用了一个全包全能的xutill来做网络请求就是坑,里面还用了looper。这下就很难用Junit4来测了。 这时候想到了Robolectric,加上Robolectric的注解,run,passed。
好的,看来Robolectric有时候还挺有用的,对于我这个渣项目来说还管用。
(仅仅对问题进行记录,如果了解决方法再更新。有大神路过请不吝解答^_^)
这样一来是不是只能用 AndroidJunit 、Espresso了