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

Laravel一次单元测试中发现的'BUG',分析并解决问题

时间:2023-03-29 13:58:15 PHP

以下代码是Laravel自带的表单验证语法。不太了解的可以先查看文档'group_num'=>'min:1|max:21'//也可以用between代替min和max。我们的预期结果是能够验证group_num字段的最小值为1,最大值为21but!!!...当我测试单元时,我发现验证通过了!//单元测试代码$warehouseId=1;$prods=[['prod_id'=>1,'group_num'=>111,'location'=>1,]];$warehouseLogic=newWarehouseLogic();$result=$warehouseLogic->addProds($warehouseId,$prods);$this->assertEquals(ErrSvc::ERR_OK,$result['code']);文档分析我们看一下文档min:value验证中的字段必须有一个最小值。字符串、数字、数组或文件大小计算都使用size方法进行评估。文章中提到使用size方法评估数字,让我们看一下size方法的文档size:value验证的字段必须具有与给定值匹配的大小。对于字符串,值对应于字符数。对于数字,值对应于给定的整数值。对于数组,大小对应于数组的计数值。对于文件,大小对应于文件大小(以kb为单位)。代码分析文档一切正常。我们通过代码来分析一下原因。我们找到验证类文件,打开:\vendor\laravel\framework\src\Illuminate\Validation\Validator.php大概在1180行,我们看到validateMin()方法validateMin()第一行代码是验证参数个数,可以通过第二行代码,调用getSize()方法,直接比较getSize()返回结果的大小,问题很严重,可能会出现在getSize()方法上。我们来看getSize()的代码getSize()。我们可以看到,如果它判断如果值是数值类型,$hasNumeric直接返回原值,如果返回原值,应该验证validateMin()方法正确,所以if条件不应该的原因true可能是因为$hasNumeric在$hasNumeric变量上调用了$this->hasRule($attribute,$this->numericRules)方法,传递了两个A参数过去$attribute:当前属性名$this->numericRules:['Numeric','Integer']那我们看看$this->hasRule()方法是干什么的?hasRule方法直接调用$this->getRule()方法,参数原封不动传递。让我们看看getRule()方法做了什么?getRule()我们知道$attribute是当前字段的名称。比如文章中使用的字段group_num$this->rules,其实就是一个字段+校验规则组成的数组。格式如下:由于第一个if语句的两个变量都是Knowingthat,所以可以判断第一个条件不成立。我们继续看下一段代码。代码是遍历当前需要校验字段的规则,格式list($rule,$parameters)=$this->parseRule($rule);假设是上图中的group_num字段,它有3条校验规则,分别是:required,min,max第一个循环$rule是Required,$parameters为空第二个循环$rule是Min,$parameters是[1]我们会发现parseRule($rule)后会在_array中判断规则,$rules为参数(['Numeric','Integer'])。上面说了,假设我们此时的字段是group_num:需要第一个规则,条件不成立;第二个规则是Min,条件仍然不成立;第三条规则是Max,条件仍然不成立!getRule()返回值:条件不成立,方法结束,没有返回值,返回值为nullhasRule()返回值:回到hasRule()方法,getRule()方法的值将be_null(),逻辑会进行非处理(!),所以返回值为false,我们再回到getSize()方法。这时我们知道$hasNumeric的值为false,所以下面的if条件不成立。最后,Laravel使用mb_strlen()为我们的数字类型的值进行了长度计算!!!解决问题现在我们知道了原因是Laravel对当前字段的所有规则都执行了in_array($rule,['Numeric','Integer']),那么解决方法就是如果我们要执行一个range检查字段的大小,我们需要把规则改成:'group_num'=>'integer|min:1|max:21'所以文章开头的验证是错误的字段数字类型!其实这不是BUG,简单来说就是Laravel的验证机制,只是Laravel的文档写的很模糊!所以大家在开发的时候,记得要仔细测试!原文出自我的博客:Laravel在一次单元测试中发现'BUG',分析解决问题-木鱼博客