网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
本章提到的接口功能测试是针对某一服务端的单个接口的功能测试。在测试过程中,我们需要关注以下几点:
-
参数校验:参数的必选校验、参数组合校验、参数类型是否合法校验、取值的边界校验;
-
接口权限校验:校验接口的使用权限是否存在水平、垂直越权;
-
返回值校验:校验返回值是否符合预期,包括返回格式、响应码、消息体、错误文案、返回数据是否正确;
-
持久化校验:落地数据的正确性校验;
-
中间件校验:缓存、消息存储逻辑校验;
-
接口逻辑验证:接口内部业务逻辑尽量做到分支覆盖。
与此同时,要想达到高效且高覆盖的测试目标,测试人员需要从用户角度出发并结合开发代码的实现,抽取出有效的等价类进行接口功能测试,如此可以减少大量时间成本,不做过度或者无效的测试。下面举一个例子来说明:
如何高效地测试一个登陆接口(用户名、密码)
与大部分人设计的用例不同,针对登陆功能,我们只设计2条用例覆盖,而不考虑用户名、密码长了短了、是否包含无效字符等各种错误条件的排列组合:
-
用例1:使用正确的用户名,密码登陆
-
用例2:使用错误的用户名或密码登陆
之所以这样设计,是因为我们提前了解到接口的实现:只是去查询数据库中否存在匹配的用户名和密码,即能够匹配成功的只有一组字符串,而用所有非法的字符串集合去数据库查询都会返回失败,这一类输入都属于异常等价类。因此我们无需去穷举入参进行测试。
def test_login_succ(self): res = self.client.login(username, password) self.assertEqual(res.code, SUCC)
3.3 接口集成测试
在单接口功能测试保障的前提下,我们需要保障接口之间交互以及数据流转的正确性。使用多服务的多接口之间的调用,就可以串联业务场景覆盖,这是功能测试覆盖最重要的手段。以下是集成测试用例设计关键点列举:
-
业务正常流程覆盖:通过各服务的接口调用来组装正常流程上的用例,保证业务流程上各分支的正常流程都被覆盖到;
-
业务异常流程覆盖:通过调用接口来覆盖业务流程上的异常分支,模拟业务节点返回异常,来测试系统的容错性,以及出错后的后续的业务补偿流程;
-
调用链路覆盖:保证系统中每条链路都覆盖到,从下游接口发起,覆盖整条链路;
-
接口时序覆盖:接口调用按照时序有效路径去设计,避免无效的路径。
举例说明,通过接口集成测试来进行测试:
新增商户报名支付源活动,费率优惠支付
测试设计:
-
正确的用例包含新增商户入网、活动报名、报名审批、触发支付源进件、费率生效、优惠支付成功等场景;
-
异常用例存在很多种情况,任一流程失败,都会导致最终业务失败;
def test_new_merchant_pay_success(self): res = self.merchant_service.create_merchant() self.assertEqual(res.code, SUCC) another_res = self.another_service.do_something(res.field) self.assertTrue(another_res, COMPLETE)
3.4 资损测试
收钱吧的业务牵涉到资金流动,如支付、分账、分润、代付等等。如果程序控制不当,就会造成严重的资金损失。引起资损的原因有很多,例如用户重复提交、程序并发问题、业务逻辑过程处理不当、金额换算处理不正确、安全漏洞等等。根据不同的业务场景,开发会选择不同的实现方案来解决问题。如唯一索引约束、分布式锁、数据库排他锁等。即便如此,测试人员仍需要进行资损相关的测试,从而保障产品质量。下面列举了三种场景,详细说明如何进行资损测试。
3.4.1 重复调用
当调用方重复发起同一笔请求,系统需要做幂等处理,确保只能扣款一次
要验证这个功能,就需要借助自动化测试的能力:模拟同一个用户顺序发起多次同样支付请求、期望只成功一次。
代码样例如下:
def test_pay_more_time(): old_balance = self.client.get_merchant_balance(merchant_id) # 获取商户余额 [self.client.pay(amount, client_sn) for _ in range(5)] # 多次发起支付 current_balance = self.client.get_merchant_balance(merchant_id) # 重新获取余额 assert current_balance == old_balance + amount # 断言商户余额只增加了1分钱
3.4.2 并发请求同一接口
当调用方并发多次同一笔支付请求,系统要确保只能扣款一次
与上一个场景的区别在于:调用请求不再友善地挨个发起,而是一哄而上,这个时候就需要用多线程模拟同用户并发调用。
代码样例如下:
def test_pay_concurrency(self): old_balance = self.client.get_merchant_balance(merchant_id) # 获取商户余额 pool = [threading.Thread(target=self.client.pay, args=(1,)) for _ in range(10)] [t.start() for t in pool] [t.join() for t in pool] # 使用多线程并发调用支付请求,金额为1分钱,并发n次 current_balance = self.client.get_merchant_balance(merchant_id) assert current_balance == old_balance + 1 # 断言商户余额只增加了1分钱
3.4.3 多种资金流动接口并发调用
对同一账户同时发起多次储值服务、核销、退款、多次请求可以成功多次
测试用例设计:
-
对同一个账户不同的操作进行并发调用;
-
并发后结果校验需满足:账户余额变化 = 累计充值金额 - 累计次核销总金额 - 累计退款金额;
代码样例如下:
def test_account() old_balance = self.client.get_merchant_balance(merchant_id) # 获取商户余额 concurrent_add(self.client, add_amount, a) # 并发储值 concurrent_reduce(self.client, reduce_amount, b) # 并发核销 concurrent_refund(self.client, refund_amount, c) # 并发退款 current_balance = self.client.get_merchant_balance(merchant_id) assert current_balance == old_balance + a*add_amount-b*reduce_amount-c*refund_amount
3.5 Mock第三方接口测试
在我们系统中,很多业务依赖三方接口,而我们无法依赖对方的测试环境来验证我们自身的逻辑,尤其是对依赖接口异常的处理。我们自研了Mock Server,这类场景的测试因此就不依赖第三方的环境。通过Mock Server控制响应异常,可以实现各种异常场景测试。比如:要模拟进件失败,支付时银行卡冻结等。
Mock Server采用高性能响应的go语言框架,而且可以动态调整返回的结果,可以很方便的集成到自动化测试中。如:
@mock("RETURN_CODE", "ACCOUNT_ERROR")def test_pay_abnormal(): response = self.client.pay() self.assertEqual(response.code, FAIL)
4. 平台化管理
4.1 自动化执行平台
我们自研了Zepar——通用的自动化测试执行平台,来解决测试用例呈现、测试计划管理、自动/手动执行的需求。通过平台化管理,大大提高了自动化用例的使用率,而且也方便其他部门的同事应用我们的自动化测试能力。
测试计划管理
执行记录
4.2 报告平台
另外我们引入了开源的测试报告平台:ReportPortal[5]。它是一个自动化测试用例日志收集、结果分析的可视化平台,可以与主流测试框架集成,如TestNG、Pytest、Junit、Nunit、SoapUI等。与此同时,该平台可以多维度统计报表,支持在线分析测试结果,并可以展示出美观的分析报告,如下图所示。
利用ReportPortal,我们强化了失败用例的分析,也能够帮助发现不稳定用例[6],及时修复,防止测试用例的腐化。
5. 防腐化措施
代码在日常的迭代中,往往会呈现出自然地腐化,从刚开始清晰明了的架构慢慢演变成四不像,越来越难维护,自动化测试用例同样避免不了陷入这种尴尬的境地。
在代码层面,我们要求遵循PEP8[7]的代码风格,用例设计上要遵循AIR[8]原则,在Function的docstring[9]中写清楚测试用例的每一个步骤,并且每次代码提交都需要进行Code Review。
在框架中,我们大量利用装饰器[10]来隐藏一些技术细节,让测试工程师尽可能只关注业务逻辑,这样可以更容易的编写自动化用例。我们鼓励写出Pythonic[11]的代码,对低质量的代码坚决Say No。
我们没有专职的自动化测试工程师,也就是说在收钱吧的测试工程师,你既要做业务测试又要维护自动化用例:)。职责清晰,责任界定也就明确,每一个测试工程师都要对他负责业务对应的自动化用例可用性负责,没有什么可推诿的。
6. 总结与展望
以上是在收钱吧项目测试中积累的有关自动化测试的一些实践与成果。目前,我们的接口测试用例总数达到30000以上,可用率超过95%,核心服务代码覆盖率更是超过70%。我们还对测试效率提出了更高的要求:随着自动化用例数量的不断增加,技术实现中出现的大量异步场景,自动化执行耗时正在增长。针对这些痛点,我们正进一步研发分布式执行框架,一劳永逸地解决这些问题。
在当下的敏捷时代,行业要求速度和质量。自动化测试的兴起无外乎成为了行业中的宝贵资源。当严谨的测试方案、完善的测试用例,遇上了高效的自动化测试手段,便成为了提升测试效率和产品质量的一把利器,不仅保证高效的回归测试,缩减大量手工测试,同时将接口用例输出给开发自测回归,给开发增添上线信心。我们将在自动化测试这条道路上不断探索、保持热忱、持续优化,为我们产品的质量保驾护航。
7. 关于作者
任斌,来自质量工程部
参考资料
[1]
Test Pyramid: https://martinfowler.com/bliki/TestPyramid.html
[2]
Testing of Microservices: https://engineering.atspotify.com/2018/01/testing-of-microservices/
[3]
Unit testing framework: https://docs.python.org/3/library/unittest.html
[4]
pytest: helps you write better programs: https://pytest.io
[5]
Reporting automated testing analytics machine learning : https://reportportal.io
[6]
Test Flakiness – Methods for identifying and dealing with flaky tests: https://engineering.atspotify.com/2019/11/test-flakiness-methods-for-identifying-and-dealing-with-flaky-tests/
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
片转存中…(img-9qSDZYG0-1715230660136)]
[外链图片转存中…(img-yu63IN8L-1715230660136)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新