Test a Procedure
This Article is taken from utPLSQL site just to
kickstart your dev ,
for more details visit utPLSQL site.
There are a couple of scenarios to consider:
- The procedure runs some code and then passes back results through the parameter list. In this case, I can write a unit test that analyzes the OUT and IN OUT argument values.
- The procedure runs some code, which changes other elements of the application (such as a database table or a file). The parameter list does not contain arguments that can be analyzed for successful execution. So to assert success, I will need to analyze/compare the data structures that have been modified.
Test Success Through Parameters
We'll start with a really simple example. I have built a procedure that accepts two dates and returns the number of seconds between them. Here it is:/*file calc_secs_between.sp */ CREATE OR REPLACE PROCEDURE calc_secs_between ( date1 IN DATE, date2 IN DATE, secs OUT NUMBER) IS BEGIN -- 24 hours in a day, -- 60 minutes in an hour, -- 60 seconds in a minute... secs := (date2 - date1) * 24 * 60 * 60; END; /After compiling my code cleanly, I generate my test package:
SQL> SET SERVEROUTPUT ON FORMAT WRAPPED SQL> exec utGen.testpkg ('calc_secs_between ') CREATE OR REPLACE PACKAGE ut_calc_secs_between IS PROCEDURE ut_setup; PROCEDURE ut_teardown; -- For each program to test... PROCEDURE ut_CALC_SECS_BETWEEN; END ut_calc_secs_between; / CREATE OR REPLACE PACKAGE BODY ut_calc_secs_between IS PROCEDURE ut_setup IS BEGIN NULL; END; PROCEDURE ut_teardown IS BEGIN NULL; END; -- For each program to test... PROCEDURE ut_CALC_SECS_BETWEEN IS BEGIN CALC_SECS_BETWEEN ( DATE1 => '' , DATE2 => '' , SECS => '' ); utAssert.this ( 'Test of CALC_SECS_BETWEEN', 'I generated the output to the screen, but it is actually easier to deposit the code directly into two separate files for package spec and body, ut_calc_secs_between.pks and ut_calc_secs_between.pkb, which I do as follows:' ); END ut_CALC_SECS_BETWEEN; END ut_calc_secs_between; /
SQL> exec utGen.testpkg ('calc_secs_between ', output_type_in => utGen.c_file)By conforming to this standard, utPLSQL can automatically compile this code before each test. I now edit the ut_calc_secs_between procedure to test for various cases:
PROCEDURE ut_CALC_SECS_BETWEEN IS secs PLS_INTEGER; BEGIN CALC_SECS_BETWEEN ( DATE1 => SYSDATE , DATE2 => SYSDATE , SECS => secs ); utAssert.eq ( 'Same dates', secs, 0 ); CALC_SECS_BETWEEN ( DATE1 => SYSDATE , DATE2 => SYSDATE+1 , SECS => secs ); utAssert.eq ( 'Exactly one day', secs, 24 * 60 * 60 ); END ut_CALC_SECS_BETWEEN;and now I can run my test:
SQL> exec utplsql.test ('calc_secs_between') . > SSSS U U CCC CCC EEEEEEE SSSS SSSS > S S U U C C C C E S S S S > S U U C C C C E S S > S U U C C E S S > SSSS U U C C EEEE SSSS SSSS > S U U C C E S S > S U U C C C C E S S > S S U U C C C C E S S S S > SSSS UUU CCC CCC EEEEEEE SSSS SSSS . SUCCESS: "calc_secs_between"Certainly, there are a variety of other conditions to test, but this should give you a good idea of how to go about it!
Test Success by Analyzing Impact
Now let's consider a more complicated situation. I have a procedure that truncates all the rows in the specified table. To do this I just use dynamic SQL, as you can see in:/*file truncit.sp */ CREATE OR REPLACE PROCEDURE truncit ( tab IN VARCHAR2, sch IN VARCHAR2 := NULL ) IS BEGIN EXECUTE IMMEDIATE 'truncate table ' || NVL (sch, USER) || '.' || tab; END; /After I run this test, I cannot simply check the value returned by the procedure. Instead, I must check to see how many rows are left in the table. Fortunately, I have another dynamic SQL utility to help me out here, one that returns the count of rows in any table: (Note that you could also use utAssert.eqqueryvalue here.)
/*file tabcount.sf */ CREATE OR REPLACE FUNCTION tabcount ( sch IN VARCHAR2, tab IN VARCHAR2) RETURN INTEGER IS retval INTEGER; BEGIN EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || sch || '.' || tab INTO retval; RETURN retval; EXCEPTION WHEN OTHERS THEN RETURN NULL; END; /So I will generate a package to test truncit and then modify the package body:
SQL> SET SERVEROUTPUT ON FORMAT WRAPPED SQL> exec utGen.testpkg ('truncit', output_type_in => utGen.c_file)To run my test, I need to truncate a table. That is an irreversible action, so I will create a "temporary" table in the setup procedure and drop it in the teardown procedure. Then I will run my code and use tabCount to validate the results:
/*file ut_truncit.pkb */ CREATE OR REPLACE PACKAGE BODY ut_truncit IS PROCEDURE ut_setup IS BEGIN EXECUTE IMMEDIATE 'CREATE TABLE temp_emp AS SELECT * FROM employee'; END; PROCEDURE ut_teardown IS BEGIN EXECUTE IMMEDIATE 'DROP TABLE temp_emp'; END; -- For each program to test... PROCEDURE ut_TRUNCIT IS BEGIN TRUNCIT ( TAB => 'temp_emp' , SCH => USER ); utAssert.eq ( 'Test of TRUNCIT', tabcount (USER, 'temp_emp'), 0 ); END ut_TRUNCIT; END ut_truncit; /