当前位置: 首页 > 后端技术 > PHP

做好API自动化测试(一)——从一个简单易用的JsonValidator开始

时间:2023-03-29 23:27:44 PHP

目前越来越流行前后端分离的开发模式,职责前端和后端也更清晰。后端提供数据,前端通过API获取数据并展示页面。前端有了更多的发挥空间,后端也可以更专注于数据处理。在这样的时代背景下,我尝试从后端的角度出发,通过一系列的文章,探讨后端开发者应该如何交付高质量的API接口,降低沟通成本,减少“联调”中可能出现的问题,确保代码质量和项目按期完成。就我目前的面试经历来说,大部分项目都没有引入自动化API测试,测试基本靠开发人员的自测和测试人员的黑盒测试。本文不讨论黑盒测试,只是表达我对自动化API测试的看法。首先,在我看来,缺乏自动化的API测试可能会存在以下问题:API实现与设计不匹配,比如字段缺失或者字段类型不正确,API无法形成完整的闭环,功能缺失,以及“联调”需要不断修改新功能,可能会导致现有API出现bug。手动回归测试既费时又麻烦。API测试是一个比较大的话题。本文主要围绕“如何让API的实现与设计一致”,谈谈我的思考和发展。JsonValidator的心路历程。起源早在两年多前,我就在思考如何测试APISchema,确保API返回的结果与预期一致。当时发现了Json-Schema这个工具,也做了一些研究,但是上手成本还是有点高,最后也没真正产出什么。然后去年在开发BlinkFramework的API测试组件时,发现Laravel中验证Json的用法非常简单优雅,Codeception也有类似的组件。所以我在想,是不是可以结合这两种方法的优点,自己开发一个JsonValidator,在保持严谨的同时,尽可能简单易用。适逢2017年新年,公司产品需要提供全新的OpenAPI,方便与合作厂商的业务对接。我觉得这是一个尝试和实现新的API测试方法的机会,所以我利用假期时间开发了一个JsonValidator的原型。读者可以在rethinkphp/json-validator查看其最新代码。JsonValidator通过简单的语法定义Json结构,然后验证给定的数据是否满足预定义的Json结构,比Json-Schema更简单易用。JsonValidator除了保证设计的简洁和优雅之外,还引入了类型系统的概念。通过开发者自定义类型,可以实现类型的复用和自由组合,让Json的校验更加方便高效。一个项目只要定义好基本类型就可以了,剩下的就是基本的积木要组装了。基本使用类型JsonValidator默认提供了7种内置类型,它们是:integer、double、boolean、string、number、array和object。开发人员还可以定义自己的复合数据类型。下面的例子定义了一个User复合类型:$validator->defineType('User',['name'=>'string','gender'=>'string','age'=>'?integer',]);这个User类型有name、gender和age三个属性,其中name和gender都是string类型,age是integer类型,但是可以为null。在这里我们添加一个?在类型前面表示该字段可以为空。除了定义复合数据类型,我们还可以定义列表类型,比如定义一个UserCollection类型,它是一个数组,数组的每个元素都是User:$validator->defineType('UserCollection',['User']);要定义列表类型,类型定义必须是一个只有一个元素的数组,并且数组的第一个元素是列表类型允许的类型。对于复杂的应用场景,我们还可以利用PHP的callable来定义更灵活的类型,如下我们定义一个timestamp类型,它验证给定的值必须是一个合法的时间字符串。$validator->defineType('timestamp',function($value){if((!is_string($value)&&!is_numeric($value))||strtotime($value)===false){returnfalse;}$date=date_parse($value);returncheckdate($date['month'],$date['day'],$date['year']);});Validation基本用法定义好数据类型后,我们就可以验证给定的数据是否符合定义,如果不符合定义,Validator会给出错误信息。使用rethinkphp\jsv\Validator;$validator=newValidator();//$validator->defineType(...)如有必要,添加自定义类型$matched=$validator->matches($data,'User');if($matched){//验证通过}else{$errors=$validator->getErrors();}在某些场景下,我们希望我们定义的类型与给定的数据完全匹配,不需要额外的字段,此时这时,可以使用JsonValidator的严格模式:$data=['name'=>'Bob','gender'=>'Male','age'=>19,'phone'=>null,//这个属性是不必要的];$matched=$validator->matches($data,'User',true);//开启严格模式var_dump($matched);//返回false此示例将无法通过验证,因为电话字段未在用户中定义。对未来的畅想本文介绍了我开发JsonValidator的背景和过程以及它的简单使用,但我也认为它的使用场景可能不仅限于此。下面是我对它未来的一些思考:类型系统和文档生成工具相结合,API文档的数据模型部分由代码直接生成,自动生成Json-Schema定义文件,更方便交叉语言使用。通过生成Json-Schema定义文件,一个自描述的RESTFulAPI得以延续……