博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Laravel一次单元测试发现的'BUG',分析并解决问题
阅读量:6255 次
发布时间:2019-06-22

本文共 2307 字,大约阅读时间需要 7 分钟。

下面这段代码是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 )。

代码分析

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

我们找到验证类的文件并打开:\vendor\laravel\framework\src\Illuminate\Validation\Validator.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文档写的很模糊!

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

原文在自己的博客:

转载地址:http://ezfsa.baihongyu.com/

你可能感兴趣的文章
使用LotusScript操作Lotus Notes RTF域
查看>>
IPv4头部结构具体解释
查看>>
帕雷托最优(Pareto optimality)、帕雷托效率(Pareto efficiency)
查看>>
PHP 面向对象
查看>>
getResourceAsStream和getResource的用法及Demo实例
查看>>
[C#] string 与 String,大 S 与小 S 之间没有什么不可言说的秘密
查看>>
javascript 自定义错误处理
查看>>
POJ 3278 Catch That Cow(BFS,板子题)
查看>>
Ubuntu下U盘只读文件系统,图标上锁,提示无法修改
查看>>
TCP/IP具体解释学习笔记--TCP的超时与重传
查看>>
C#设计模式之十一享元模式(Flyweight Pattern)【结构型】
查看>>
基于zookeeper简单实现分布式锁
查看>>
Makefile:160: recipe for target 'all' failed (Ubuntu 16.06 + Opencv3.2)解决办法
查看>>
a WebSite for MapXtreme2005 Crack
查看>>
几种函数调用方式
查看>>
【MySQL】MySQL 常用语法之锁表与解锁表
查看>>
【142】阿蛮歌霸使用技巧
查看>>
HTTP 请求报文 响应报文
查看>>
[转载] 程序员必看:请不要做浮躁的人 24法则
查看>>
JavaWeb_JavaEE_命名规则
查看>>