存储过程测试流程--以MySQL为例

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 同C/C++/Java等语言编写的代码一样,用SQL语言编写的存储过程也需要进行充分的测试。本文以实际的MySQL存储过程为例,介绍存储过程测试的整个流程。

同C/C++/Java等语言编写的代码一样,用SQL语言编写的存储过程也需要进行充分的测试。本文以实际的MySQL存储过程为例,介绍存储过程测试的整个流程。

在本文中,需要被测试的存储过程如下:

drop procedure if exists pr_dealtestnum;
delimiter //

create procedure pr_dealtestnum
(
    in    p_boxnumber    varchar(30),
    out   p_result       int,
    out   p_outusertype  int
)
pr_dealtestnum_label:begin
    declare   p_boxnumcount    int;
    declare   p_usertype       int;

    set p_boxnumcount = 0;
    set p_usertype     = 0;
    set p_outusertype  = 0;

    select count(*) into p_boxnumcount from tb_testnum where boxnumber=p_boxnumber;
    if p_boxnumcount > 0 then
    begin
        select usertype into p_usertype from tb_testnum where boxnumber=p_boxnumber;

        set p_outusertype =  (p_usertype+1)/10*10;

        set p_result = 0;
    end;
    else
    begin
        set p_result = 1;
    end;
    end if;

    leave pr_dealtestnum_label;
end;
//
delimiter ;
select 'create procedure pr_dealtestnum ok';

在存储过程中使用到的表tb_testnum如下:

drop table if exists tb_testnum;

create table tb_testnum
(
    boxnumber  varchar(30)  not null,
    usertype   int          not null                                                                                  
);
create unique index idx1_tb_testnum on tb_testnum(boxnumber);

其中,usertype字段的值必须要大于1。

对存储过程进行测试大致遵循以下步骤:
第一步,按照存储过程的输入和输出参数设置正确的调用样式。

第二步,根据调用时的输入参数值来向相关的表中插入测试数据。

第三步,执行第一步中的存储过程调用语句,查看执行结果是否正确,并根据该结果来修改存储过程。

下面具体进行说明。

第一步
就本存储过程pr_dealtestnum而言,根据程序逻辑,我们可设置如下调用语句:

call pr_dealtestnum('2344273520',@1,@2);select @1,@2;
call pr_dealtestnum('2344273521',@1,@2);select @1,@2;
call pr_dealtestnum('2344273522',@1,@2);select @1,@2;
call pr_dealtestnum('2344273523',@1,@2);select @1,@2;
call pr_dealtestnum('2344273524',@1,@2);select @1,@2;
call pr_dealtestnum('2344273525',@1,@2);select @1,@2;
call pr_dealtestnum('2344273526',@1,@2);select @1,@2;
call pr_dealtestnum('2344273527',@1,@2);select @1,@2;
call pr_dealtestnum('2344273528',@1,@2);select @1,@2;
call pr_dealtestnum('2344273529',@1,@2);select @1,@2;
call pr_dealtestnum('2344273530',@1,@2);select @1,@2;
call pr_dealtestnum('2344273531',@1,@2);select @1,@2;
call pr_dealtestnum('2344273532',@1,@2);select @1,@2;
call pr_dealtestnum('2344273533',@1,@2);select @1,@2;
call pr_dealtestnum('2344273534',@1,@2);select @1,@2;
call pr_dealtestnum('15696192523',@1,@2);select @1,@2;

大家还可以设置更多的调用语句,其目的是为了对存储过程进行更加充分的测试。

第二步
根据第一步设置的调用语句,兼顾程序逻辑,我们可执行如下语句向表tb_testnum中插入数据:

insert into tb_testnum(boxnumber,usertype) values('2344273520',1);
insert into tb_testnum(boxnumber,usertype) values('2344273521',3);
insert into tb_testnum(boxnumber,usertype) values('2344273522',4);
insert into tb_testnum(boxnumber,usertype) values('2344273523',5);
insert into tb_testnum(boxnumber,usertype) values('2344273524',7);
insert into tb_testnum(boxnumber,usertype) values('2344273525',8);
insert into tb_testnum(boxnumber,usertype) values('2344273526',9);
insert into tb_testnum(boxnumber,usertype) values('2344273527',10);
insert into tb_testnum(boxnumber,usertype) values('2344273528',11);
insert into tb_testnum(boxnumber,usertype) values('2344273529',13);
insert into tb_testnum(boxnumber,usertype) values('2344273530',14);
insert into tb_testnum(boxnumber,usertype) values('2344273531',15);
insert into tb_testnum(boxnumber,usertype) values('2344273532',26);
insert into tb_testnum(boxnumber,usertype) values('2344273533',52);
insert into tb_testnum(boxnumber,usertype) values('2344273534',87);

第三步
在向表tb_testnum中插入数据之后,我们开始逐条执行第一步中的存储过程调用语句,以验证存储过程代码逻辑的正确性。

首先执行“call pr_dealtestnum(‘2344273520’,@1,@2);select @1,@2;”,结果如下:

mysql> call pr_dealtestnum('2344273520',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |    2 |
+------+------+
1 row in set (0.00 sec)

我们来分析执行结果是否是我们想要的。将入参“2344273520”带入存储过程中,首先是“select count(*) into p_boxnumcount from tb_testnum where boxnumber=’2344273520’;”,此时“boxnumcount”变量的值为1(因为之前执行过语句“insert into tb_testnum(boxnumber,usertype) values(‘2344273520’,1);”);接着,程序进入“if p_boxnumcount > 0 then”分支,执行“select usertype into p_usertype from tb_testnum where boxnumber=’2344273520’;”语句,“p_usertype”变量的值为1;然后,执行“set p_outusertype = (1+1)/10*10;”语句,即“p_outusertype”变量的值为“2/10*10”,进一步计算为“0*10”,最终结果为0;最后,执行“set p_result = 0;”语句,“p_result”变量的值为0。因此,最终两个输出参数的值都应该为0。

但是,实际的结果是,两个输出参数的值分别为0和2,是哪里出了问题呢?我们重点分析“(1+1)/10*10”的结果,将之在MySQL中单独执行,结果如下:

mysql> select (1+1)/10*10;
+-------------+
| (1+1)/10*10 |
+-------------+
|      2.0000 |
+-------------+
1 row in set (0.00 sec)

mysql> select (1+1)/10;
+----------+
| (1+1)/10 |
+----------+
|   0.2000 |
+----------+
1 row in set (0.00 sec)

我们可以看到,“(1+1)/10”的结果并不是我们预想的0,而是0.2,看来,在MySQL中,两个整数相除并不是只取结果的整数部分,而是取了小数点后面的若干位。

那么,如果我们只想要整数部分,应该怎么办呢?此时,可以用floor()函数,即“floor((1+1)/10)”就是取了结果的整数部分,如下所示:

mysql> select floor((1+1)/10);
+-----------------+
| floor((1+1)/10) |
+-----------------+
|               0 |
+-----------------+
1 row in set (0.00 sec

现在,我们据此修改存储过程,修改之后如下所示:

drop procedure if exists pr_dealtestnum;
delimiter //

create procedure pr_dealtestnum
(
    in    p_boxnumber    varchar(30),
    out   p_result       int,
    out   p_outusertype  int
)
pr_dealtestnum_label:begin
    declare   p_boxnumcount    int;
    declare   p_usertype       int;

    set p_boxnumcount = 0;
    set p_usertype    = 0;
    set p_outusertype = 0;

    select count(*) into p_boxnumcount from tb_testnum where boxnumber=p_boxnumber;
    if p_boxnumcount > 0 then
    begin
        select usertype into p_usertype from tb_testnum where boxnumber=p_boxnumber;

        set p_outusertype =  floor((p_usertype+1)/10)*10;

        set p_result = 0;
    end;
    else
    begin
        set p_result = 1;
    end;
    end if;

    leave pr_dealtestnum_label;
end;
//
delimiter ;
select 'create procedure pr_dealtestnum ok';

再次执行“call pr_dealtestnum(‘2344273520’,@1,@2);select @1,@2;”,结果如下:

mysql> call pr_dealtestnum('2344273520',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |    0 |
+------+------+
1 row in set (0.00 sec)

此时的结果就是我们想要的。

我们可以继续执行在第一步中设置的其它存储过程调用语句,结果如下:

mysql> call pr_dealtestnum('2344273521',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |    0 |
+------+------+
1 row in set (0.00 sec)

mysql> call pr_dealtestnum('2344273522',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |    0 |
+------+------+
1 row in set (0.00 sec)

mysql> call pr_dealtestnum('2344273523',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |    0 |
+------+------+
1 row in set (0.00 sec)

mysql> call pr_dealtestnum('2344273524',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |    0 |
+------+------+
1 row in set (0.00 sec)

mysql> call pr_dealtestnum('2344273525',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |    0 |
+------+------+
1 row in set (0.00 sec)

mysql> call pr_dealtestnum('2344273526',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |   10 |
+------+------+
1 row in set (0.00 sec)

mysql> call pr_dealtestnum('2344273527',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |   10 |
+------+------+
1 row in set (0.00 sec)

mysql> call pr_dealtestnum('2344273528',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |   10 |
+------+------+
1 row in set (0.00 sec)

mysql> call pr_dealtestnum('2344273529',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |   10 |
+------+------+
1 row in set (0.00 sec)

mysql> call pr_dealtestnum('2344273530',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |   10 |
+------+------+
1 row in set (0.00 sec)

mysql> call pr_dealtestnum('2344273531',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |   10 |
+------+------+
1 row in set (0.00 sec)

mysql> call pr_dealtestnum('2344273532',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |   20 |
+------+------+
1 row in set (0.00 sec)

mysql> call pr_dealtestnum('2344273533',@1,@2);select @1,@2;
Query OK, 1 row affected (0.00 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |   50 |
+------+------+
1 row in set (0.00 sec)

mysql> call pr_dealtestnum('2344273534',@1,@2);select @1,@2;
Query OK, 1 row affected (0.01 sec)

+------+------+
| @1   | @2   |
+------+------+
|    0 |   80 |
+------+------+
1 row in set (0.00 sec)
mysql> call pr_dealtestnum('15696192523',@1,@2);select @1,@2;
Query OK, 1 row affected (0.01 sec)

+------+------+
| @1   | @2   |
+------+------+
|    1 |    0 |
+------+------+
1 row in set (0.00 sec)

可以看到,修改之后的存储过程的执行结果就是正确的了。最后一条调用语句“call pr_dealtestnum(‘15696192523’,@1,@2);select @1,@2;”中,因为输入参数中的“15696192523”对应的数据在tb_testnum表中不存在,因此程序进入了“else”分支,“p_result”变量的值就为1,而“p_outusertype”变量的值为0。

总结
存储过程的测试方法和用其它编程语言编写的程序的测试方法是一样的,都需要我们在充分理解程序逻辑的基础上构造完整的、多样化的测试用例,并在测试的过程中根据测试的结果来修改程序,以达到我们预期的结果,并最终满足用户的需求。

需要强调的是,在软件开发过程中,我们测试代码的时间,很可能会多余我们编写代码的时间,大家一定要耐着性子忍受测试代码过程中的“孤独感”。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
22天前
|
存储 Java 关系型数据库
java调用mysql存储过程
在 Java 中调用 MySQL 存储过程主要借助 JDBC(Java Database Connectivity)。其核心原理是通过 JDBC 与 MySQL 建立连接,调用存储过程并处理结果。具体步骤包括:加载 JDBC 驱动、建立数据库连接、创建 CallableStatement 对象、设置存储过程参数并执行调用。此过程实现了 Java 程序与 MySQL 数据库的高效交互。
|
27天前
|
SQL 存储 关系型数据库
MySQL原理简介—1.SQL的执行流程
本文介绍了MySQL驱动、数据库连接池及SQL执行流程的关键组件和作用。主要内容包括:MySQL驱动用于建立Java系统与数据库的网络连接;数据库连接池提高多线程并发访问效率;MySQL中的连接池维护多个数据库连接并进行权限验证;网络连接由线程处理,监听请求并读取数据;SQL接口负责执行SQL语句;查询解析器将SQL语句解析为可执行逻辑;查询优化器选择最优查询路径;存储引擎接口负责实际的数据操作;执行器根据优化后的执行计划调用存储引擎接口完成SQL语句的执行。整个流程确保了高效、安全地处理SQL请求。
176 76
|
3月前
|
SQL 存储 缓存
MySQL执行流程
本文介绍了MySQL的执行流程,分为server层和引擎层。server层包含连接器、查询缓存、解析器、预处理器、优化器等组件,负责SQL的接收、解析、优化及执行;引擎层负责数据的存储与读取。文章详细解释了各组件的功能,如连接器负责用户身份认证,查询缓存提高查询效率,解析器进行SQL的词法和语法分析,预处理器验证表和字段的存在性,优化器选择最优执行计划,最终由查询执行引擎完成查询并将结果返回给客户端。
MySQL执行流程
|
19天前
|
编解码 缓存 Prometheus
「ximagine」业余爱好者的非专业显示器测试流程规范,同时也是本账号输出内容的数据来源!如何测试显示器?荒岛整理总结出多种测试方法和注意事项,以及粗浅的原理解析!
本期内容为「ximagine」频道《显示器测试流程》的规范及标准,我们主要使用Calman、DisplayCAL、i1Profiler等软件及CA410、Spyder X、i1Pro 2等设备,是我们目前制作内容数据的重要来源,我们深知所做的仍是比较表面的活儿,和工程师、科研人员相比有着不小的差距,测试并不复杂,但是相当繁琐,收集整理测试无不花费大量时间精力,内容不完善或者有错误的地方,希望大佬指出我们好改进!
79 16
「ximagine」业余爱好者的非专业显示器测试流程规范,同时也是本账号输出内容的数据来源!如何测试显示器?荒岛整理总结出多种测试方法和注意事项,以及粗浅的原理解析!
|
26天前
|
存储 SQL 缓存
MySQL原理简介—2.InnoDB架构原理和执行流程
本文介绍了MySQL中更新语句的执行流程及其背后的机制,主要包括: 1. **更新语句的执行流程**:从SQL解析到执行器调用InnoDB存储引擎接口。 2. **Buffer Pool缓冲池**:缓存磁盘数据,减少磁盘I/O。 3. **Undo日志**:记录更新前的数据,支持事务回滚。 4. **Redo日志**:确保事务持久性,防止宕机导致的数据丢失。 5. **Binlog日志**:记录逻辑操作,用于数据恢复和主从复制。 6. **事务提交机制**:包括redo日志和binlog日志的刷盘策略,确保数据一致性。 7. **后台IO线程**:将内存中的脏数据异步刷入磁盘。
|
2月前
|
Dart 前端开发 Android开发
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
41 1
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
4月前
|
存储 SQL 关系型数据库
[MySQL]存储过程
本文介绍了存储过程的概念、优点和缺点,并通过具体示例详细讲解了存储过程的创建、使用和调用方法。此外,还介绍了游标的定义和使用,帮助读者更好地理解和应用存储过程。文章旨在为读者提供一个学习和使用存储过程的实用指南。
413 18
[MySQL]存储过程
|
4月前
|
关系型数据库 MySQL 测试技术
【赵渝强老师】MySQL的基准测试与sysbench
本文介绍了MySQL数据库的基准测试及其重要性,并详细讲解了如何使用sysbench工具进行测试。内容涵盖sysbench的安装、基本使用方法,以及具体测试MySQL数据库的步骤,包括创建测试数据库、准备测试数据、执行测试和清理测试数据。通过这些步骤,可以帮助读者掌握如何有效地评估MySQL数据库的性能。
180 5
|
5月前
|
机器学习/深度学习 监控 计算机视觉
目标检测实战(八): 使用YOLOv7完成对图像的目标检测任务(从数据准备到训练测试部署的完整流程)
本文介绍了如何使用YOLOv7进行目标检测,包括环境搭建、数据集准备、模型训练、验证、测试以及常见错误的解决方法。YOLOv7以其高效性能和准确率在目标检测领域受到关注,适用于自动驾驶、安防监控等场景。文中提供了源码和论文链接,以及详细的步骤说明,适合深度学习实践者参考。
1054 1
目标检测实战(八): 使用YOLOv7完成对图像的目标检测任务(从数据准备到训练测试部署的完整流程)
|
4月前
|
存储 SQL NoSQL