This is my own personal test framework for testing PL/SQL modules. It's been around since before TAP had a name, actually. In the past I have built a public test subroutine right into packages which I then call from a short wrapper SQL*Plus script for testing. (I usually call the wrapper script t.sql, so I can test with three keystrokes. :) ) At times I've found it better to put the tests into the t.sql script itself.
Maybe somebody can clean this up and make something better out of it.
Note that IS is a reserved word in SQL, so I couldn't name a routine is within the T package. And so I named it tis: name of the package + "is", or "tis" if you like to use older English and sound like you're reciting the Night before Christmas. :)
CREATE OR REPLACE PACKAGE T IS PROCEDURE plan; PROCEDURE end_tests; PROCEDURE ok(condition BOOLEAN, name VARCHAR2 := NULL); PROCEDURE pass(name VARCHAR2 := NULL); PROCEDURE fail(name VARCHAR2 := NULL); PROCEDURE todo(condition BOOLEAN, name VARCHAR2 := NULL); PROCEDURE tis(got VARCHAR2, expected VARCHAR2, name VARCHAR2 := NULL); PROCEDURE tis(got BOOLEAN, expected BOOLEAN, name VARCHAR2 := NULL); PROCEDURE set_verbose(p_on BOOLEAN); END T; / show errors
CREATE OR REPLACE PACKAGE BODY T IS test_count INTEGER := 0; traffic_light BOOLEAN := TRUE; success_count INTEGER := 0; start_time DATE; verbose BOOLEAN := TRUE; PROCEDURE plan IS BEGIN start_time := SYSDATE; test_count := 0; traffic_light := TRUE; success_count := 0; END plan; PROCEDURE end_tests IS success_percentage VARCHAR2(7); interval NUMBER; BEGIN success_percentage := TO_CHAR(100 * success_count / test_count, '999D99'); DBMS_OUTPUT.PUT_LINE(success_percentage || ' percent of tests succeeded.'); interval := SYSDATE - start_time; interval := interval * 24 * 60 * 60; DBMS_OUTPUT.PUT_LINE(TO_CHAR(interval, '999D99') || ' seconds elapsed'); IF traffic_light THEN DBMS_OUTPUT.PUT_LINE('green light'); ELSE DBMS_OUTPUT.PUT_LINE('RED LIGHT'); END IF; END end_tests; PROCEDURE ok(condition BOOLEAN, name VARCHAR2 := NULL) IS BEGIN IF condition THEN pass(name); ELSE fail(name); END IF; END ok; FUNCTION name_output(name VARCHAR2 := NULL) RETURN VARCHAR2 IS BEGIN IF name IS NOT NULL THEN RETURN ' - ' || name; ELSE RETURN NULL; END IF; END name_output; PROCEDURE pass(name VARCHAR2 := NULL) IS BEGIN test_count := test_count + 1; success_count := success_count + 1; IF verbose THEN DBMS_OUTPUT.PUT_LINE('ok ' || TO_CHAR(test_count) || name_output(name)); END IF; END pass; PROCEDURE fail(name VARCHAR2 := NULL) IS BEGIN test_count := test_count + 1; DBMS_OUTPUT.PUT_LINE('not ok ' || TO_CHAR(test_count) || name_output(name)); traffic_light := FALSE; END fail; PROCEDURE todo_pass(name VARCHAR2 := NULL) IS BEGIN test_count := test_count + 1; success_count := success_count + 1; DBMS_OUTPUT.PUT_LINE('ok ' || TO_CHAR(test_count) || name_output(name) || ' # UNEXPECTEDLY SUCCEEDED'); END todo_pass; PROCEDURE todo_fail(name VARCHAR2 := NULL) IS BEGIN test_count := test_count + 1; DBMS_OUTPUT.PUT_LINE('not ok ' || TO_CHAR(test_count) || name_output(name) || ' # TODO'); -- don't change traffic_light END todo_fail; PROCEDURE todo(condition BOOLEAN, name VARCHAR2 := NULL) IS BEGIN IF condition THEN todo_pass(name); ELSE todo_fail(name); END IF; END todo; PROCEDURE tis_fail(got VARCHAR2, expected VARCHAR2, name VARCHAR2 := NULL) IS BEGIN fail(name); DBMS_OUTPUT.PUT_LINE('# got: ' || nvl(got, 'NULL')); DBMS_OUTPUT.PUT_LINE('# expected: ' || nvl(expected, 'NULL')); END tis_fail; PROCEDURE tis(got VARCHAR2, expected VARCHAR2, name VARCHAR2 := NULL) IS BEGIN IF got = expected THEN pass(name); ELSE tis_fail(got, expected, name); END IF; END tis; FUNCTION bto_char(p BOOLEAN) RETURN VARCHAR2 IS BEGIN IF p THEN RETURN 'TRUE'; ELSIF NOT p THEN RETURN 'FALSE'; ELSE RETURN NULL; END IF; END bto_char; PROCEDURE tis(got BOOLEAN, expected BOOLEAN, name VARCHAR2 := NULL) IS BEGIN IF got = expected THEN pass(name); ELSE tis_fail(bto_char(got), bto_char(expected), name); END IF; END tis; PROCEDURE set_verbose(p_on BOOLEAN) IS BEGIN verbose := p_on; END set_verbose; END T; / show errors