使用Mockito、Robolectric和RxJava及Retrofit进行单元测试
原文出处:http://www.jianshu.com/p/b00586534fc1
本文只是对Mockito、Robolectric的测试使用进行简单介绍,主要还是围绕着Http测试这一块,特别是RxJava和Retrofit与上述两个测试框架的结合使用。
PS:RxJava这一块我看的是大头鬼前辈的文章,也推荐对RxJava感兴趣的朋友去看。
本文结构
build.gradle结构
配置并编写单元测试
api测试
build.gralde结构
robolectric3.0版本使用的时候遇到个问题,然后大概查阅了解到是gradle插件1.3.0版本与robolectric的冲突,所以这个demo里面用到的gradle.tools用的是1.2.3版本。
然后就是用到了java8的插件,所以配置了一下,这里就不用多说了。
配置并编写单元测试
如图所示,打开Build Variants选项卡,然后将Test Artifact的类型选为Unit Test。
然后创建对应的包名,巴拉巴拉。
然后开始写第一个测试,下面就直接贴代码了。
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
public class MockitoTest {
@Before
public void setUp(){
}
@Test
public void MocksTest(){
TestSubscriber<Mock> testSubscriber = new TestSubscriber<>();
getMocks().subscribe(testSubscriber);
assertThat(testSubscriber.getOnNextEvents().size(),is(3));
}
@Test
public void ListMocksTest(){
TestSubscriber<Mock> testSubscriber = new TestSubscriber<>();
getListMocks().flatMap(Observable::from).subscribe(testSubscriber);
assertThat(testSubscriber.getOnNextEvents().size(), is(3));
}
private Observable<Mock> getMocks(){
return Observable.just(new Mock(),new Mock(),new Mock());
}
private Observable<List<Mock>> getListMocks(){
List<Mock> list = new ArrayList<>();
list.add(new Mock());
list.add(new Mock());
list.add(new Mock());
return Observable.just(list);
}
class Mock{
}
}
上面代码里面是两个测试方法,然后有两个获取测试数据的函数,这两个函数其实是类似的,分别是返回Observable和Observable<List>,这里两个测试方法其实目的是一样的,都是判断个数是否为3。这里其实就是想展示使用变换操作符FlatMap,将Observable<List>转换为Observable。
还有就是import了需要的assertThat和is。这里再额外说下,TestSubscriber这个类是rx包名下的类,是用于Observable类测试用的,这里再额外提一下,一个别人写的类,可以实现相同的功能,有兴趣的朋友可以看下这篇文章。
api测试
下面贴api相关的测试代码。
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNot.not;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(RobolectricGradleTestRunner.class) @Config(constants = BuildConfig.class)
public class ApiTest {
Github mGithub = GithubFactory.getSingleton();//走真实数据的接口
Github mMockGithub;
Client mMockClient;
@Before public void setUp() {
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.serializeNulls()
.create();
mMockClient = mock(Client.class);
RequestInterceptor requestInterceptor = request -> request.addHeader("User-Agent",
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0");
RestAdapter restAdapter = new RestAdapter.Builder().setClient(mMockClient)
.setLogLevel(RestAdapter.LogLevel.FULL)
.setEndpoint("https://api.github.com")
.setConverter(new GsonConverter(gson))
.setRequestInterceptor(requestInterceptor)
.build();
mMockGithub = restAdapter.create(Github.class);
}
@Test public void reposTest1() throws IOException {
String mockJsonResult =
"这里模拟数据太长就不贴了,请看代码吧";
FakeHttp.addPendingHttpResponse(200, mockJsonResult);
HttpGet httpGet = new HttpGet("http://www.baidu.com");
HttpResponse httpResponse = new DefaultHttpClient().execute(httpGet);
String result = EntityUtils.toString(httpResponse.getEntity());
System.out.print(result);
assertThat(result, is(mockJsonResult));
}
//这个是走真实网络返回的数据
@Test public void reposTest2() {
List<Repo> list = mGithub.listRepos("devinshine");
assertThat(list.size(), is(not(0)));
System.out.print(list.size());
}
//这个是走真实网络返回的数据
@Test public void reposTestByObservable() {
int size = mGithub.listRepos2Observable("devinshine")
.flatMap(Observable::from)
.count()
.toBlocking()
.single();
assertThat(size, is(not(0)));
System.out.print(size);
//下面代码是会报错的
//TestSubscriber<Repo> testSubscriber = new TestSubscriber<>();
//mGithub.listRepos2Observable("devinshine")
// .flatMap(Observable::from)
// .subscribe(testSubscriber);
//assertThat(testSubscriber.getOnNextEvents().size(),is(not(0)));
}
//这是走模拟数据
@Test public void reposTestByMockClient() throws IOException {
String mockJsonResult =
"这里模拟数据太长就不贴了,请看代码吧";
Response response =
new Response("http://www.baidu.com", 200, "nothing", Collections.EMPTY_LIST,
new TypedByteArray("application/json", mockJsonResult.getBytes()));
when(mMockClient.execute(Matchers.anyObject())).thenReturn(response);
int size = mMockGithub.listRepos2Observable("devinshine")
.flatMap(Observable::from)
.count()
.toBlocking()
.single();
assertThat(size, is(1));
}
上面有4个测试函数。
第一个测试函数就是最基本的模拟http层的返回内容,使用的robolectric自带的方法。
第二个测试函数是使用retrofit进行网络请求,是直接返回网络真实请求的数据,这个也十分的简单易懂。
第三个测试函数是使用retrofit和RxJava的Observable,但是是用异步的方式获取数据,也是网络真实请求的数据,这个时候我们要获取返回的数据个数的话,就要将异步转为同步,不然的话直接去获取个数是会为0的;
第四个测试函数和第三个函数整体类似,只是走的不是真实网络请求,而是通过模拟数据的形式进行测试,这里用到了mockito的when方法,mockito这个框架在这里就不多作介绍,简单的说下when和thenReturn的作用是什么意思,用大白话来解释就是,当在做某事的时候,返回某个值。
那么
when(mMockClient.execute(Matchers.anyObject())).thenReturn(response);
这段就很好理解了,当mMockClient执行execute方法的时候,返回response这个值,其实也就是替换真实的网络请求。
至此,一个简单的demo就写完了,具体相关框架的引申讲解本次就不再介绍了,相信网上已经有很多介绍了,如果有机会我再补充一些我所理解TDD运用在Android开发上的看法(挖坑);
demo地址:https://github.com/DevinShine/MockTest
参考资料:
1.https://touk.pl/blog/2014/02/26/mock-retrofit-using-dagger-and-mockito/
2.https://github.com/bboyfeiyu/android-tech-frontier/blob/master/issue-19/RxJava-Observables%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95.md
3.http://qiuguo0205.iteye.com/blog/1443344
4.http://www.slideshare.net/ssuser72c3b0/rxjava-android-rxjava
5.http://mcxiaoke.gitbooks.io/rxdocs/content/Observables.htmlttp://support.ghost.org/installing-ghost-linux/
6.http://blog.csdn.net/lzyzsd/article/details/41833541