前言

在开发一个功能之前,一般会有一个设计、架构的过程,因为大杂烩的开发方式导致代码难以测试和维护。
我们一般采用MV*的方式组织代码,不同功能的代码放到不同的模块里,容易测试和维护。
Picasso,OkHttp,Fresco等一般使用Junit+Robolectric+mockito做单元测试。

Robolectric原理

Robolectric最大的好处是可以在PC机上运行android的单元测试,其通过实现一套JVM能运行的Android代码,然后在unit test运行的时候去截取android相关的代码调用,然后转到他们的他们实现的代码去执行这个调用的过程。

举个例子说明一下,比如android里面有个类叫TextView,他们实现了一个类叫ShadowTextView。这个类基本上实现了TextView的所有公共接口,假设你在unit test里面写到String text = textView.getText().toString();。在这个unit test运行的时候,Robolectric会自动判断你调用了Android相关的代码textView.getText(),然后这个调用过程在底层截取了,转到ShadowTextView的getText实现。而ShadowTextView是真正实现了getText这个方法的,所以这个过程便可以正常执行。

除了实现Android里面的类的现有接口,Robolectric还做了另外一件事情,极大地方便了unit testing的工作。那就是他们给每个Shadow类额外增加了很多接口,可以读取对应的Android类的一些状态。比如我们知道ImageView有一个方法叫setImageResource(resourceId),然而并没有一个对应的getter方法叫getImageResourceId(),这样你是没有办法测试这个ImageView是不是显示了你想要的image。而在Robolectric实现的对应的ShadowImageView里面,则提供了getImageResourceId()这个接口。你可以用来测试它是不是正确的显示了你想要的Image.

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RunWith(RobolectricTestRunner.class)
public class MyActivityTest {

@Test
public void clickingButton_shouldChangeResultsViewText() throws Exception {
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!");
}
}