资讯专栏INFORMATION COLUMN

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

zhiwei / 2177人阅读

摘要:下面这段代码是自带的表单验证的语法,不太了解的可以先查看文档也可以使用替换和我们期望的结果是能校验字段最小值是,最大值是当我单元测试的时候发现,竟然校验通过了单元测试代码文档分析我们看一下文档验证中的字段必须具有最小值。

下面这段代码是Laravel自带的表单验证的语法,不太了解的可以先查看文档

"group_num" => "min:1|max:21"  // 也可以使用between替换min和max

我们期望的结果是能校验group_num字段最小值是1,最大值是21

but !!!

...

当我单元测试的时候发现,竟然校验通过了!

// 单元测试代码

$warehouseId = 1;   
$prods = [      
    [         
        "prod_id" => 1,      
        "group_num" => 111,      
        "location" => 1,   
    ]
];   
$warehouseLogic = new WarehouseLogic();   
$result = $warehouseLogic->addProds($warehouseId, $prods);    
$this->assertEquals(ErrSvc::ERR_OK, $result["code"]);
文档分析

我们看一下文档

min:value

验证中的字段必须具有最小值。字符串、数字、数组或是文件大小的计算方式都用 size 方法进行评估。

文章提到数字使用size方法进行评估,我们看一下size方法的文档

size:value

验证的字段必须具有与给定值匹配的大小。对于字符串来说,value 对应于字符数。对于数字来说,value 对应于给定的整数值。对于数组来说,
size 对应的是数组的 count 值。对文件来说,size 对应的是文件大小(单位 kb )。

代码分析

文档一切正常,我们翻一翻代码试着分析下原因

我们找到验证类的文件并打开:vendorlaravelframeworksrcIlluminateValidationValidator.php

大约在1180行,我们看到validateMin()方法

validateMin()

第一行代码,是对参数个数进行验证的,可以pass掉

第二行代码,调用了getSize()方法,并对getSize()返回结果直接进行大小比较,问题很有可能就出现在getSize()方法身上

我们看一下getSize()的代码

getSize()

我们可以看到if里面判断了如果值是数字类型并且$hasNumeric就直接返回原始值,如果返回原始值的话,validateMin()方法应该会正确校验,所以if条件应该是不成立

原因很可能就在$hasNumeric这个变量上

$hasNumeric调用了$this->hasRule($attribute, $this->numericRules)方法,并传了两个参数过去

$attribute:当前属性名

$this->numericRules:["Numeric", "Integer"]

然后我们看一下$this->hasRule()方法究竟做了什么?

hasRule方法直接调用了$this->getRule()方法,并且将参数原封不动传递过去

我们看一下getRule()方法干了什么?

getRule()

我们已知$attribute是当前字段名,比如文章举例用的字段group_num

$this->rules其实就是字段+校验规则拼装的数组,格式如下:

既然第一个if语句的两个变量都知道了,我们就能判断出第一个条件是不成立的,我们继续看接下来的代码

代码是对当前需要校验字段的规则进行遍历,并且格式化

list($rule, $parameters) = $this->parseRule($rule);

假设是上图中的group_num字段,他有3个校验规则,分别是:required、min、max

第一次循环$rule就是Required,$parameters为空

第二次循环$rule就是Min,$parameters就是[1]

我们会发现parseRule($rule)后,会对规则进行in_array的判断,$rules是参数(["Numeric", "Integer"])上文有写

假设我们此时的字段是group_num:

第一个规则是required,条件不成立;

第二个规则是Min,条件依然不成立;

第三个规则是Max,条件还是不成立!

getRule()返回值:

条件都不成立,方法走完,没有任何返回值,返回值为null

hasRule()返回值:

回到hasRule()方法,会对getRule()方法值进行is_null(),并进行逻辑非处理(!),所以返回值为false

我们接着回到getSize()方法,此时我们就知道$hasNumeric的值是false

所以下面的if条件都不成立,最后Laravel使用mb_strlen()对我们数字类型的值进行了长度计算!!!

解决问题

既然我们知道原因在于Laravel对当前字段所有规则进行了in_array($rule, ["Numeric", "Integer"])

所以解决思路就是,如果我们要对字段进行大小进行范围校验,我们需要把规则修改成:

"group_num" => "integer|min:1|max:21"

所以文章开头的校验,对于数值类型的字段,是错误的!

其实这不是一个BUG,单纯的是Laravel的校验机制,不过Laravel文档写的很模糊!

所以大家在开发的时候记得一定要认真测试

原文在自己的博客:Laravel一次单元测试发现的’BUG’,分析并解决问题 - 木鱼博客

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/28914.html

相关文章

  • input[type='file']在html5中打开文件选择框缓慢问题

    摘要:最近在项目中引用了一个新标准上传附件的插件,使用过程中发现了一个很有意思也很头疼的问题,第一次点击时瞬间就可以打开文件选择框,之后再点击则需要等待恐怖的以上备注使用的是浏览器版本这是核心部分代码,经过二次封装的。 最近在项目中引用了一个html5新标准上传附件的插件,使用过程中发现了一个很有意思也很头疼的问题,第一次点击时瞬间就可以打开文件选择框,之后再点击则需要等待恐怖的8s以上(备...

    BenCHou 评论0 收藏0
  • JS 中为啥 ['1', '7', '11

    摘要:如果我们把非布尔值作为条件呢打开控制台并运行上述代码,会打印说明条件为真值。在中,真值指的是在布尔值上下文中转换后的值为真的值。两个能够建立元素间一一对应的集合称为互相对等集合。 showImg(https://segmentfault.com/img/bVbtSvt?w=720&h=360); 为了保证可读性,本文采用音译而非直译。 Javascript 一直是神奇的语言。 不相信我...

    yuanzhanghu 评论0 收藏0
  • Laravel】[错误解决] 'Class AppConsoleKernel do

    摘要:今天用更改了的命名空间名字,然后又用恢复到了原来的命名空间名。结果直接导致以下错误问题解决确定你的引导程序没问题在项目根目录执行命令解决方案来自传送门为什么要执行,参考深入 今天用php artisan app:name 更改了app的命名空间名字,然后又用git恢复到了原来的App命名空间名。 结果直接导致以下错误:Fatal error: Uncaught exception Re...

    chadLi 评论0 收藏0
  • ECharts xAxis.type='time'时间轴时卡顿问题

    摘要:原文首发于我的个人网站卡顿问题出现背景中主要耗能设置为折线图轴数据量控件最开始轴为类目轴,最近根据情况想改为时间轴卡顿主要表现在显示和拖动时。初步分析是为导致,因为切换回后就卡顿问题消失。 原文首发于我的个人网站: https://lonhon.top/ 卡顿问题出现背景: ECharts^4.0.4 + Vue^2.5.9 option中主要耗能设置为:折线图 + Y轴2 + se...

    happyhuangjinjin 评论0 收藏0

发表评论

0条评论

zhiwei

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<