使用Retrofit和Mockito进行可靠的Android API测试

简介: 测试与API交互的HTTP调用是一件令人生厌的复杂事情。测试一个真实的Web服务器时,一大堆问题随之产生:脆性测试(brittle test,因为网络或API本身的问题而导致的测试失败)、速度减慢测试(slow test,每一次HTTP调用都要花费好几秒)和不完全测试(“如何触发一个速率限制越界用例?想一想,我只希望速率限制会起作用……”)。

测试与API交互的HTTP调用是一件令人生厌的复杂事情。测试一个真实的Web服务器时,一大堆问题随之产生:脆性测试(brittle test,因为网络或API本身的问题而导致的测试失败)、速度减慢测试(slow test,每一次HTTP调用都要花费好几秒)和不完全测试(“如何触发一个速率限制越界用例?想一想,我只希望速率限制会起作用……”)。

像Android这样的平台HTTP理应是异步调用,问题会变得更加复杂。如果在这些测试组合中添加计时器,那么你就准备好在测试API调用上认输吧。


解决这些问题并且练习这些HTTP调用的一个绝妙方法是,使用一个很好的Mockito(一个Java测试双库 double library)通用程序:ArgumentCaptor

ArgumentCaptor与混合测试双有几分相似;有点类似存根(stub),也有点类似侦听程序(spy),但不完全是其中任何一个。可以使用参数捕获器捕获并存储传给mock/stub的参数。然而这里真正的亮点是对捕获的参数进行方法调用,对于像Retrofit回调有很大帮助。


译注:Retrofit是一个Android & Java的类型安全REST客户端。

有了Retrofit,我们可以发起一个API调用并提供一个回调方法。当服务器做出响应时,Mockito会使用响应数据执行回调方法。

下面这些代码使用Github API查询用户代码仓库:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

getApi().repositories("swanson"newCallback<List<Repository>>() {

 

    @Override

    publicvoidsuccess(List<Repository> repositories, Response response) {

        if(repositories.isEmpty()) {

          displaySadMessage();

        }

 

        mAdapter.setRepositories(repositories);

    }

 

    @Override

    publicvoidfailure(RetrofitError retrofitError) {

        displayErrorMessage();

    }

});

这里有三个我们想要测试的用例:理想路径(happy path,获取一些代码仓库并把传递给适配器)、错误路径(error path,向用户提示服务器错误)、特殊用例(special case, 向用户提示没有代码仓库错误)。


如果你的测试依赖于在真实的API服务器,那么第二和第三个用例会很复杂。我了解到最近GitHub有一些DDOS问题,但你肯定不能依赖它们来测试你的错误用例!

然而我们可以通过ArgumentCaptor捕获回调参数,进而完全控制发送的数据。

看一下对理想路径的测试(我用的是Robolectri,建议你也尝试一下):

1

2

3

4

5

6

7

8

9

Mockito.verify(mockApi).repositories(Mockito.anyString(), cb.capture());

 

List<Repository> testRepos = newArrayList<Repository>();

testRepos.add(newRepository("rails""ruby"newOwner("dhh")));

testRepos.add(newRepository("android""java"newOwner("google")));

 

cb.getValue().success(testRepos, null);

 

assertThat(activity.getListAdapter()).hasCount(2);

captor(cb)捕获到回调,调用getValue()方法以后,通过success方法向它传递一些伪对象(dummy object)。

你可能会感叹“啊哈(原来可以这么简单)”。呵呵,如果没有也没关系。接下来可以看一下对错误路径的测试:

1

2

3

4

5

Mockito.verify(mockApi).repositories(Mockito.anyString(), cb.capture());

 

cb.getValue().failure(null);

 

assertThat(ShadowToast.getTextOfLatestToast()).contains("Failed");

像之前一样,我们捕获了回调。但是这一次我们调用了failure方法,它模拟了一个API错误。如果我们需要更有针对性的错误处理(例如:如果返回状态是401,就重定向再登陆;如果是500, 弹出一条普通的系统错误消息),可以通过创建合适RetrofitError对象作为failure调用的参数。


目前为止,ArgumentCaptor的威力真的很赞。我们完全控制了捕获到的对象,并且能够给这些对象设置任意的数据或者触发任意想要测试的错误。

为了让内容更加丰富,下面是对一个特殊用例的测试:

1

2

3

4

5

6

7

8

Mockito.verify(mockApi).repositories(Mockito.anyString(), cb.capture());

 

List<Repository> noRepos = newArrayList<Repository>();

 

cb.getValue().success(noRepos, null);

 

assertThat(ShadowToast.getTextOfLatestToast()).contains("No repos :(");

assertThat(activity.getListAdapter()).isEmpty();

(你可以在GitHub上找到示例的全部源码和工程文件)。

有一个特殊细节要注意:如果在声明捕获器时使用了Mockito注解,

1

2

@Captor

privateArgumentCaptor<Callback<List<Repository>>> cb;

请确保在设置中的某个地方添加了下面代码:

1

MockitoAnnotations.initMocks(this);

这种测试方法完全符合书中提到的所有特点:快速、健壮、易于使用。我们还可以通过它很容易地测试项目中很少出现的边缘情况(会话超时、服务器维护、特殊值),确保我们的应用正常运行。


虽然本文示例是专门针对某种栈(Android、Robolectric、Retrofit、Mockito),但是类似的方法几乎适用于任何应用。

相关文章
|
3月前
|
人工智能 数据可视化 测试技术
Postman 性能测试教程:快速上手 API 压测
本文介绍API上线后因高频调用导致服务器告警,通过Postman与Apifox进行压力测试排查性能瓶颈。对比两款工具在批量请求、断言验证、可视化报告等方面的优劣,探讨API性能优化策略及行业未来发展方向。
Postman 性能测试教程:快速上手 API 压测
|
5月前
|
人工智能 监控 安全
API安全测试工具:数字经济的免疫防线
API安全面临漏洞盲区、配置错误与合规碎片三大挑战,传统手段难抵新型风险。破局需构建智能漏洞探针、配置审计中枢与合规映射引擎三位一体防御矩阵。Burp Suite、Noname Security、Traceable AI与板栗看板等工具助力企业实现自动化检测、精准响应与高效合规,打造API安全免疫体系。
|
4月前
|
XML 安全 测试技术
【干货满满】分享什么是API接口测试
API接口测试是验证应用程序编程接口功能、性能、安全性及兼容性的关键环节,通过模拟请求并验证响应结果,确保接口能正确处理各种输入和场景。测试内容涵盖功能验证、性能评估、安全防护、兼容性验证及系统可靠性。相比UI测试,API测试无需界面依赖,支持数据驱动与自动化,适用于持续集成流程。常见接口类型包括RESTful、SOAP和GraphQL API,广泛应用于电商、金融及社交平台,保障系统间数据交互的安全与高效。
|
5月前
|
JSON JavaScript 测试技术
用Postman玩转电商API:一键测试+自动化请求教程
Postman 是电商 API 测试的高效工具,涵盖基础配置、自动化测试、环境管理与请求自动化,助你快速提升开发效率。
|
3月前
|
人工智能 数据可视化 测试技术
AI 时代 API 自动化测试实战:Postman 断言的核心技巧与实战应用
AI 时代 API 自动化测试实战:Postman 断言的核心技巧与实战应用
512 11
|
5月前
|
存储 机器学习/深度学习 API
Android API Level 到底是什么?和安卓什么关系?应用发布如何知道自己的版本?优雅草卓伊凡
Android API Level 到底是什么?和安卓什么关系?应用发布如何知道自己的版本?优雅草卓伊凡
870 31
Android API Level 到底是什么?和安卓什么关系?应用发布如何知道自己的版本?优雅草卓伊凡
|
9月前
|
缓存 监控 负载均衡
如何提升 API 性能:来自 Java 和测试开发者的优化建议
本文探讨了如何优化API响应时间,提升用户体验。通过缓存(如Redis/Memcached)、减少数据负载(REST过滤字段或GraphQL精确请求)、负载均衡(Nginx/AWS等工具)、数据压缩(Gzip/Brotli)、限流节流、监控性能(Apipost/New Relic等工具)、升级基础设施、减少第三方依赖、优化数据库查询及采用异步处理等方式,可显著提高API速度。快速响应的API不仅让用户满意,还能增强应用整体性能。
|
8月前
|
监控 测试技术 数据库连接
RunnerGo API 性能测试实战:从问题到解决的全链路剖析
API性能测试是保障软件系统稳定性与用户体验的关键环节。本文详细探讨了使用RunnerGo全栈测试平台进行API性能测试的全流程,涵盖测试计划创建、场景设计、执行分析及优化改进。通过电商平台促销活动的实际案例,展示了如何设置测试目标、选择压测模式并分析结果。针对发现的性能瓶颈,提出了代码优化、数据库调优、服务器资源配置和缓存策略等解决方案。最终,系统性能显著提升,满足高并发需求。持续关注与优化API性能,对系统稳定运行至关重要。
|
4月前
|
监控 安全 测试技术
API测试工具评测:Apipost与Apifox的优劣深度解读
本文对比了Apipost与Apifox在API设计、数据建模、代码生成、测试能力、协作权限、性能监控、插件生态、文档管理及安全合规等方面的差异。Apifox在专业性、自动化、扩展性及团队协作上表现更优,尤其适合中大型项目与复杂管理需求,而Apipost功能较基础,适用于轻量级使用场景。
|
4月前
|
JSON 安全 测试技术
什么是API接口测试?这可能是全网最全的教程了!
API 是应用程序间的“中间人”,用于实现通信和数据交换。随着微服务架构的普及,API 数量激增,其质量对系统稳定性至关重要。API 测试可验证功能、性能与安全性,帮助开发者在部署前发现并修复问题,提升系统可靠性。测试内容包括请求方法、URL、请求头、请求体、响应状态码与响应数据等。常用工具如 Postman、AREX 可辅助测试,确保 API 在不同场景下的正确性与稳定性。