序言及回顾
长期测试经验告诉我们,大量的错误发生在输入或输出范围的边界值上,而不是在输入输出范围的内部。
本文是系列总结第二篇,列举3个测试时遇到的边界值bug的典型例子~
边界值Bug1
Bug描述: 判断内存大小能否容纳字符串时,判断条件未正确处理边界值,导致边界值情况下,使用sprintf函数向目标内存写数据,会丢失最后一个字符。
if((size_t)dest_size
{
LOG_ERR(“%s failed. Dest buffer_size is not enough.”,_func_);
return ERR_BUF_NOT_ENOUGH;
}
如上,代码中是想判断目标内存区大小能否存得下即将放入的字符串,如果空间不足,则返回一个错误;否则,则使用sprintf将字符串直接写入目标内存。
出问题的关键在于这里在判断时忽略了字符串末尾的\0。
而当实际的目标内存空间大小为11个字节时,不满足以上判断条件,于是认为目标内存是足够容纳字符串的,于是通过sprintf写入后最终的结果变成这样(最后一个字符d被截取掉了):
解决:将条件判断中的
边界值Bug2
Bug描述:发送消息次数小于最大重试次数时,继续重试;达到最大重试次数后退出。代码中如果一直重试失败,最后实际发送次数会比最大重试次数多1.
代码中当发送消息失败时,会判断重试次数是否小于最大重试次数,如果是,则记录一条日志并重试。初始时,try_send_times=0,当if(try_send_times
if (status == -1)
{
// send message failed
if (errno == EAGAIN)
{
if (try_send_times
{
LOG_WARN("msg queue is full! try_send_times:%d",try_send_times);
usleep(5000);
try_send_times++;
continue;
}
else
{
LOG_ERR("msg queue is full! try send message times are large than MAX TIMES: %d",MAX_SEND_MSG_TIMES);
}
}
else
{
LOG_ERR("Send msg failed! Err: %s", strerror(errno));
}
}
}
解决:将try_send_times初始值修改为1.
边界值Bug3
Bug描述:自增操作写在判断语句中,导致最后日志记录次数比实际多1.
if(try_get_times++
{
….
}
….
if (try_get_times >= _max_repeat_read_times)
{
LOG_ERR("%s: Error value of key: %s, Execute %d times", __func__,key, try_get_times);
}
如上,代码中每执行一次判断,try_get_times都会自增1,即使不满足判断条件后,即try_get_times=_max_repeat_read_times时,条件不满足不再执行if语句块内容,但变量值仍然会加1,这样在最后记录日志时,try_get_times=_max_repeat_read_times+1。
解决:将自增语句放在if块内;或者在最后记录日志时改成记录_max_repeat_read_times的值。
总结
以上是在测试时遇到的边界值问题,除了最表浅的判断条件处之外,问题更容易隐藏在上下文逻辑中,测试时仅仅关注判断条件,循环条件等本身是不够的,需要具体情况具体分析。
Qtest是360旗下的专业测试团队!
是WEB平台部测试技术平台化、效率化的先锋力量!
领取专属 10元无门槛券
私享最新 技术干货