Android单元测试(五):网络接口测试

 温馨提示:如果你不太熟悉单元测试,可以先看下之前四篇基础框架使用。便于你更好的理解下面的内容。

在平日的开发中,我们用后台写好给我们接口去获取数据。虽然我们有一些请求接口的工具,可以快速的拿到返回数据。但是在一些异常情况的处理上就不太方便了。我列出以下几个痛点:

  • 快速的查看返回数据与数据的处理。(一般我们都是将写好的代码跑到手机上,点击到对应页面的对应按钮)

  • 异常信息的返回与处理。比如一个接口返回一个列表数据,如果列表为空呢?(找后台给我们模拟数据)网速不好呢?(不知道怎么搞…)网络异常呢?(关闭网络)

  • 后台有部分接口没有写好,你就只能等他了。

不知道上面的这三点有没有戳到你的痛处。如果扎心了,那么老铁你就有必要掌握今天的内容。

1.请求接口

我们就使用网络请求三件套(retrofit + okhttp + rxjava2)来举例。

首先添加一下依赖,同时记得加网络权限。

  //RxJavacompile 'io.reactivex.rxjava2:rxjava:2.1.7'//RxAndroidcompile 'io.reactivex.rxjava2:rxandroid:2.0.1'//okhttpcompile "com.squareup.okhttp3:okhttp:3.9.1"//Retrofitcompile ("com.squareup.retrofit2:retrofit:2.3.0"){exclude module: 'okhttp'}compile ("com.squareup.retrofit2:adapter-rxjava2:2.3.0"){exclude module: 'rxjava'}compile "com.squareup.retrofit2:converter-gson:2.3.0"

测试接口:

public interface GithubApi {String BASE_URL = "https://api.github.com/";@GET("users/{username}")Observable<User> getUser(@Path("username") String username);
}

Retrofit的初始化,我们使用LoggingInterceptor来打印返回数据。

public class GithubService {private static Retrofit retrofit = new Retrofit.Builder().baseUrl(GithubApi.BASE_URL).client(getOkHttpClient()).addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();public static GithubApi createGithubService() {return retrofit.create(GithubApi.class);}private static OkHttpClient getOkHttpClient(){return new OkHttpClient.Builder().addInterceptor(new LoggingInterceptor()).build();}
}

测试代码:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 23)
public class ResponseTest {@Beforepublic void setUp() {ShadowLog.stream = System.out;initRxJava2();}private void initRxJava2() {RxJavaPlugins.reset();RxJavaPlugins.setIoSchedulerHandler(new Function<Scheduler, Scheduler>() {@Overridepublic Scheduler apply(Scheduler scheduler) throws Exception {return Schedulers.trampoline();}});RxAndroidPlugins.reset();RxAndroidPlugins.setMainThreadSchedulerHandler(new Function<Scheduler, Scheduler>() {@Overridepublic Scheduler apply(Scheduler scheduler) throws Exception {return Schedulers.trampoline();}});}@Testpublic void getUserTest() {GithubService.createGithubService().getUser("simplezhli").subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<User>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(User user) {assertEquals("唯鹿", user.name);assertEquals("http://blog.csdn.net/qq_17766199", user.blog);}@Overridepublic void onError(Throwable e) {Log.e("Test", e.toString());}@Overridepublic void onComplete() {}});}
}

上面的代码中,因为网络请求是异步的,所以我们直接测试是不能直接拿到数据,因此无法打印出Log以及测试。所以我们使用initRxJava2()方法将异步转化为同步。这样我们就可以看到返回信息。测试结果如下:

上面的例子为了简单直观的说明,所以将请求接口的方法写到了测试类中,实际中我们可以Mock方法所在的类直接调用请求方法。配合Robolectric对View控件的状态进行测试。

如果你觉得每次测试都要加initRxJava2这段方法很麻烦,你可以抽象出来,或者使用@Rule

public class RxJavaRule implements TestRule {@Overridepublic Statement apply(final Statement base, Description description) {return new Statement() {@Overridepublic void evaluate() throws Throwable {RxJavaPlugins.reset();RxJavaPlugins.setIoSchedulerHandler(new Function<Scheduler, Scheduler>() {@Overridepublic Scheduler apply(Scheduler scheduler) throws Exception {return Schedulers.trampoline();}});RxAndroidPlugins.reset();RxAndroidPlugins.setMainThreadSchedulerHandler(new Function<Scheduler, Scheduler>() {@Overridepublic Scheduler apply(Scheduler scheduler) throws Exception {return Schedulers.trampoline();}});base.evaluate();}};}
}

2.模拟数据

1.使用拦截器模拟数据

利用okhttp的拦截器模拟响应数据。

public class MockInterceptor implements Interceptor {private final String responseString; //你要模拟返回的数据public MockInterceptor(String responseString) {this.responseString = responseString;}@Overridepublic Response intercept(Interceptor.Chain chain) throws IOException {Response response = new Response.Builder().code(200).message(responseString).request(chain.request()).protocol(Protocol.HTTP_1_0).body(ResponseBody.create(MediaType.parse("application/json"), responseString.getBytes())).addHeader("content-type", "application/json").build();return response;}
}

测试代码:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 23)
public class MockGithubServiceTest {private GithubApi mockGithubService;@Rulepublic RxJavaRule rule = new RxJavaRule();@Beforepublic void setUp() throws URISyntaxException {ShadowLog.stream = System.out;//定义Http Client,并添加拦截器OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new LoggingInterceptor()).addInterceptor(new MockInterceptor("json数据"))//<-- 添加拦截器.build();//设置Http ClientRetrofit retrofit = new Retrofit.Builder().baseUrl(GithubApi.BASE_URL).client(okHttpClient).addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();mockGithubService = retrofit.create(GithubApi.class);}@Testpublic void getUserTest() throws Exception {mockGithubService.getUser("weilu") //<-- 这里传入错误的用户名.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<User>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(User user) {assertEquals("唯鹿", user.name);assertEquals("http://blog.csdn.net/qq_17766199", user.blog);}@Overridepublic void onError(Throwable e) {Log.e("Test", e.toString());}@Overridepublic void onComplete() {}});}}

虽然我们传入了错误的用户名,但是我们模拟的响应信息已经提前设定好了,所以测试结果不变。

利用这个思路,我们可以修改MockInterceptor的code,模拟404的情况。

2.MockWebServer

MockWebServer是square出品的跟随okhttp一起发布,用来Mock服务器行为的库。MockWebServer能帮我们做的事情:

  • 可以设置http response的header、body、status code等。
  • 可以记录接收到的请求,获取请求的body、header、method、path、HTTP version。
  • 可以模拟网速慢的网络环境。
  • 提供Dispatcher,让mockWebServer可以根据不同的请求进行不同的反馈。

添加依赖:

testCompile 'com.squareup.okhttp3:mockwebserver:3.9.1'

测试代码:

@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 23)
public class MockWebServerTest {private GithubApi mockGithubService;private MockWebServer server;@Rulepublic RxJavaRule rule = new RxJavaRule();@Beforepublic void setUp(){ShadowLog.stream = System.out;// 创建一个 MockWebServerserver = new MockWebServer();//设置响应,默认返回http code是 200MockResponse mockResponse = new MockResponse().addHeader("Content-Type", "application/json;charset=utf-8").addHeader("Cache-Control", "no-cache").setBody("{\"id\": 12456431, " +" \"name\": \"唯鹿\"," +" \"blog\": \"http://blog.csdn.net/qq_17766199\"}");MockResponse mockResponse1 = new MockResponse().addHeader("Content-Type", "application/json;charset=utf-8").setResponseCode(404).throttleBody(5, 1, TimeUnit.SECONDS) //一秒传递5个字节,模拟网速慢的情况.setBody("{\"error\": \"网络异常\"}");server.enqueue(mockResponse); //成功响应server.enqueue(mockResponse1);//失败响应OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new LoggingInterceptor()).build();Retrofit retrofit = new Retrofit.Builder().baseUrl("http://" + server.getHostName() + ":" + server.getPort() + "/") //设置对应的Host与端口号.client(okHttpClient).addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();mockGithubService = retrofit.create(GithubApi.class);}@Testpublic void getUserTest() throws Exception {//请求不变mockGithubService.getUser("simplezhli").subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<User>() {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(User user) {assertEquals("唯鹿", user.name);assertEquals("http://blog.csdn.net/qq_17766199", user.blog);}@Overridepublic void onError(Throwable e) {Log.e("Test", e.toString());}@Overridepublic void onComplete() {}});//验证我们的请求客户端是否按预期生成了请求RecordedRequest request = server.takeRequest();assertEquals("GET /users/simplezhli HTTP/1.1", request.getRequestLine());assertEquals("okhttp/3.9.1", request.getHeader("User-Agent"));// 关闭服务server.shutdown();}
}

代码中的注释写的很清楚了,就不用过多的解释了,使用起来非常的简单。

执行结果(成功):

失败结果:

默认情况下 MockWebServer 预置的响应是先进先出的。这样可能对你的测试有限制,这时可以通过Dispatcher来处理,比如通过请求的路径来选择转发。

    Dispatcher dispatcher = new Dispatcher() {@Overridepublic MockResponse dispatch(RecordedRequest request) throws InterruptedException {if (request.getPath().equals("/users/simplezhli")){return new MockResponse().addHeader("Content-Type", "application/json;charset=utf-8").addHeader("Cache-Control", "no-cache").setBody("{\"id\": 12456431, " +" \"name\": \"唯鹿\"," +" \"blog\": \"http://blog.csdn.net/qq_17766199\"}");} else {return new MockResponse().addHeader("Content-Type", "application/json;charset=utf-8").setResponseCode(404).throttleBody(5, 1, TimeUnit.SECONDS) //一秒传递5个字节.setBody("{\"error\": \"网络异常\"}");}}};server.setDispatcher(dispatcher); //设置Dispatcher

通过上面的例子,是不是可以很好的解决你的痛点,希望对你有帮助。只要我们有和后台有开发文档,约定好数据格式与字段名,那么我们可以更敏捷的去做我们的开发。

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/642700.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

xxe漏洞之scms靶场漏洞

xxe-scms 代码审核 &#xff08;1&#xff09;全局搜索simplexml_load_string simplexml_load_string--将XML字符串解释为对象 &#xff08;2&#xff09;查看源代码 ID1 $GLOBALS[HTTP_RAW_POST_DATA]就相当于file_get_contents("php://input"); 因此这里就存…

Java面试题之基础篇

文章目录 一&#xff1a;谈谈你对面向对象的理解二&#xff1a;JDK、JRE、JVM三者区别和联系三&#xff1a;和equals比较四&#xff1a;hashCode与equals五&#xff1a;final六&#xff1a;String、StringBuffer、StringBuilder七&#xff1a;重载与重写的区别&#xff1f;八&a…

慎用“from pwn import *”!和re库findall方法重名引发的问题

今天搓一个sage脚本遇到一个很无语的问题&#xff0c;经过调试&#xff0c;发现是pwntools库中的findall方法和re库中的findall方法重名导致的。这两个findall方法的用法完全不一样&#xff0c;稍有不慎就会踩坑。 文章目录 区分问题引发如何规避 区分 re 是 Python 中用于处理…

mockjs使用(2)

mockjs使用&#xff08;1&#xff09; 4、Mock 4.1 Mock.mock() 根据数据模版生成模拟数据 Mock.mock( rurl?, rtype?, template|function(options) )问号代表该参数不必填 4.1.1 各参数及其默认值 rurl: 不必填。表示需要拦截的URL&#xff0c;可以使URL字符串或URL正…

Java-SPI机制

SPI基本概念 SPI&#xff08;Service Provider Interface&#xff09;是一种服务发现机制&#xff0c;为某个接口寻找服务实现的机制。这有点类似 IoC 的思想&#xff0c;将装配的控制权移交到了程序之外。SPI 将服务接口和具体的服务实现分离开来&#xff0c;将服务调用方和服…

Linux 强大的网络命令:nc命令操作方法

Netcat&#xff08;或简称nc&#xff09;是一个强大的网络工具&#xff0c;它在Linux系统中广泛使用&#xff0c;可用于创建各种网络连接。它被描述为"网络的瑞士军刀"&#xff0c;因为它的功能非常灵活&#xff0c;可以在网络中执行多种任务。 在大多数Linux发行版中…

速锐得解码匹配吉利枫叶80V/60S远程控制汽车应用B端市场

吉利枫叶80V/60S这两款车平时是不多见的&#xff0c;因为吉利枫叶的定位就的B端市场&#xff0c;包括了公务用车、共享出行、网约车、大客户定制&#xff0c;所以&#xff0c;好风凭借力&#xff0c;送我上青云&#xff0c;吉利在默默地发着一笔小财&#xff0c;或者说拓宽了更…

Go 复合数据类型

1. 数组&#xff08;array&#xff09;&#xff08;OK&#xff09; 数组数组的概念数组是具有固定长度且拥有零个或多个相同数据类型元素的序列 i. 元素的数据类型相同 ii. 长度固定的序列 iii. 零个或多个元素的序列 与 slice 对比 由于数组的长度固定&#xff0c;所以在 G…

2023年春秋杯网络安全联赛冬季赛 Writeup

文章目录 Webezezez_phppicup Misc谁偷吃了外卖modules明文混淆 Pwnnmanagerbook Reupx2023 CryptoCF is Crypto Faker 挑战题勒索流量Ezdede 可信计算 Web ezezez_php 反序列化打redis主从复制RCE&#xff1a;https://www.cnblogs.com/xiaozi/p/13089906.html <?php c…

教育大模型浪潮中,松鼠Ai的“智适应”故事好讲吗?

“计算机对于学校和教育产生的影响&#xff0c;远低于预期&#xff0c;要改变这一点&#xff0c;计算机和移动设备必须致力于提供更多个性化的课程&#xff0c;并提供有启发性的反馈。” 这是2011年5月份乔布斯与比尔盖茨最后一次会面时的记录&#xff0c;当时的电脑还十分落后…

大型语言模型 (LLM)全解读

一、大型语言模型&#xff08;Large Language Model&#xff09;定义 大型语言模型 是一种深度学习算法&#xff0c;可以执行各种自然语言处理 (NLP) 任务。 大型语言模型底层使用多个转换器模型&#xff0c; 底层转换器是一组神经网络。 大型语言模型是使用海量数据集进行训练…

Yuliverse:引领区块链游戏新篇章!

数据源&#xff1a;Yuliverse Dashboard 作者&#xff1a;lesleyfootprint.network 什么是 Yuliverse Yuliverse 是一款元宇宙游戏的先锋&#xff0c;是一款主打 Explore to earn 和 Social to earn 的链游。 这是一款能让你边玩边赚钱的免费区块链游戏&#xff0c;得到 LI…

如何在WordPress中使用 AI 进行 SEO(12 个工具)

您想在 WordPress 中使用 AI 进行 SEO 吗&#xff1f; 人工智能正在对 SEO 行业产生重大影响。已经有优秀的人工智能 SEO 工具&#xff0c;您可以使用它们来提高您的 SEO 排名&#xff0c;而无需付出太多努力。 在本文中&#xff0c;我们将向您展示如何通过我们精心挑选的工具…

代码随想录第十八天 513 找树左下角的值 112 路径之和 106 从中序与后序遍历序列构造二叉树

LeetCode 513 找树左下角的值 题目描述 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7 思路 1.确定递…

MySQL用户管理

1.用户 1.1 用户信息 mysql> use mysql; Database changed mysql> select host,user,authentication_string from user; --------------------------------------------------------------------- | host | user | authentication_string | --…

ubuntu 20.04 aarch64 平台交叉编译 libffi 库

前言 由于打算交叉编译 python&#xff0c;但是依赖 libffi 库&#xff0c;也就是 libffi 库也需要交叉编译 环境&#xff1a; ubuntu 20.04 交叉编译工具链&#xff1a;这里使用 musl libc 的 gcc 交叉编译工具链&#xff0c;aarch64-linux-musleabi-gcc&#xff0c;gcc 版本…

智谱AI官网再升级,GLM-4,智能体,AI作图长文档全部搞定

创建智能体 智能体体验中心 可以看到智谱AI也推出了自己的智能体&#xff0c;并且官方内置了丰富多样的智能体供大家免费体验。 GLM-4 原生支持自动联网、图片生成、数据分析等复杂任务&#xff0c;现开放体验中&#xff0c;快来开启更多精彩。写一篇《繁花》的影评&#xf…

[每日一题] 01.23 - 画矩形

画矩形 height,width,c,d input().split() height,width,d int(height),int(width),int(d) lis [c * width if d else c * (width - 2) c for i in range(height) ]lis: ##### # # # # ##### 或 # # # # # # # #if not d:print(c * width)for i in lis[1:-1…

1986-Minimum error thresholding

1 论文简介 《Minimum error thresholding》是由 Kittler 和 Illingworth 于 1986 年发布在 Pattern Recognition 上的一篇论文。该论文假设原始图像中待分割的目标和背景的分布服从高斯分布&#xff0c;然后根据最小误差思想构建最小误差目标函数&#xff0c;最后取目标函数最…