存儲過程測試流程--以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。
對存儲過程進行測試大致遵循以下步驟:
***步,按照存儲過程的輸入和輸出參數(shù)設置正確的調(diào)用樣式。
第二步,根據(jù)調(diào)用時的輸入?yún)?shù)值來向相關的表中插入測試數(shù)據(jù)。
第三步,執(zhí)行***步中的存儲過程調(diào)用語句,查看執(zhí)行結果是否正確,并根據(jù)該結果來修改存儲過程。
下面具體進行說明。
***步
就本存儲過程pr_dealtestnum而言,根據(jù)程序邏輯,我們可設置如下調(diào)用語句:
- 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;
大家還可以設置更多的調(diào)用語句,其目的是為了對存儲過程進行更加充分的測試。
第二步
根據(jù)***步設置的調(diào)用語句,兼顧程序邏輯,我們可執(zhí)行如下語句向表tb_testnum中插入數(shù)據(jù):
- 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中插入數(shù)據(jù)之后,我們開始逐條執(zhí)行***步中的存儲過程調(diào)用語句,以驗證存儲過程代碼邏輯的正確性。
首先執(zhí)行“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)
我們來分析執(zhí)行結果是否是我們想要的。將入?yún)?ldquo;2344273520”帶入存儲過程中,首先是“select count(*) into p_boxnumcount from tb_testnum where boxnumber=’2344273520’;”,此時“boxnumcount”變量的值為1(因為之前執(zhí)行過語句“insert into tb_testnum(boxnumber,usertype) values(‘2344273520’,1);”);接著,程序進入“if p_boxnumcount > 0 then”分支,執(zhí)行“select usertype into p_usertype from tb_testnum where boxnumber=’2344273520’;”語句,“p_usertype”變量的值為1;然后,執(zhí)行“set p_outusertype = (1+1)/10*10;”語句,即“p_outusertype”變量的值為“2/10*10”,進一步計算為“0*10”,最終結果為0;***,執(zhí)行“set p_result = 0;”語句,“p_result”變量的值為0。因此,最終兩個輸出參數(shù)的值都應該為0。
但是,實際的結果是,兩個輸出參數(shù)的值分別為0和2,是哪里出了問題呢?我們重點分析“(1+1)/10*10”的結果,將之在MySQL中單獨執(zhí)行,結果如下:
- 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中,兩個整數(shù)相除并不是只取結果的整數(shù)部分,而是取了小數(shù)點后面的若干位。
那么,如果我們只想要整數(shù)部分,應該怎么辦呢?此時,可以用floor()函數(shù),即“floor((1+1)/10)”就是取了結果的整數(shù)部分,如下所示:
- mysql> select floor((1+1)/10);
- +-----------------+
- | floor((1+1)/10) |
- +-----------------+
- | 0 |
- +-----------------+
- 1 row in set (0.00 sec
現(xiàn)在,我們據(jù)此修改存儲過程,修改之后如下所示:
- 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';
再次執(zhí)行“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)
此時的結果就是我們想要的。
我們可以繼續(xù)執(zhí)行在***步中設置的其它存儲過程調(diào)用語句,結果如下:
- 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)
可以看到,修改之后的存儲過程的執(zhí)行結果就是正確的了。***一條調(diào)用語句“call pr_dealtestnum(‘15696192523’,@1,@2);select @1,@2;”中,因為輸入?yún)?shù)中的“15696192523”對應的數(shù)據(jù)在tb_testnum表中不存在,因此程序進入了“else”分支,“p_result”變量的值就為1,而“p_outusertype”變量的值為0。
總結
存儲過程的測試方法和用其它編程語言編寫的程序的測試方法是一樣的,都需要我們在充分理解程序邏輯的基礎上構造完整的、多樣化的測試用例,并在測試的過程中根據(jù)測試的結果來修改程序,以達到我們預期的結果,并最終滿足用戶的需求。
需要強調(diào)的是,在軟件開發(fā)過程中,我們測試代碼的時間,很可能會多余我們編寫代碼的時間,大家一定要耐著性子忍受測試代碼過程中的“孤獨感”。
【本文是51CTO專欄作者周兆熊的原創(chuàng)文章,作者微信公眾號:周氏邏輯(logiczhou)】