utPLSQL
A Unit Testing Framework for
Oracle PL/SQL Code
Achieving PL/SQL Excellence
Steven Feuerstein
Original creator of utPLSQL, not currently active on project (2016)
Visit the Github Repo for utPLSQL: http://https://github.com/utPLSQL
Aw, Gee, Mom, do I have to test
my code? Only if you want:
 Successful applications
– That is the whole point, after all.
 Successful applications on time
– "We don't have time to test"? Hah! Solid testing improves the
chances of putting out quality code on time.
 Developer and user confidence
– It's a wonderful feeling to know that our code really and truly
works.
– Our users then love us and support us.
Different Kinds of Tests
 Functional, System, Integration tests
– Written by the software customer, it answers the question
“What do I need to verify before I am confident this feature
works?”
 Many other types of tests
– Stress tests – real-world workload testing
– Monkey tests – tests responses to unusual conditions
– Parallel tests – compares behavior of new and old systems
 And then there are unit tests...
– Written by the developer, they test
individual units (procedure or function
in PL/SQL)
The focus in
this
presentation.
Wouldn't it be great if...
 It was easy to construct tests
– An agreed-upon and effective approach to test construction that
everyone can understand and follow
 It was easy to run tests
– And see the results, instantly and automatically.
 Testing were completely integrated into my
development, QA and maintenance processes
– No program goes to QA until it has passed a battery of tests
– Anyone can maintain with confidence, because my test suite
automatically validates my changes
POLL
 How do you (or your team) unit test your PL/SQL
code today?
 Possible answers:
– Everyone does their own thing and we hope for the
best.
– Our users test our code.
– We have a formal test process
– We use automated testing software
Typical Development
and Testing Scenario
 Let's walk through a typical development/test
flow, critique it, and then take a look at how you
might do the same thing with utPLSQL
 We'll use a very simple example:
– building an improvement to the SUBSTR function
Improving upon SUBSTR
 SUBSTR returns the sub-string specified by start
position and number of characters.
just10 := SUBSTR (full_string, 3, 10);
Grab 10 characters staring
from 3rd position
 Suppose I have the starting and
ending positions (or even sub-
strings). How do I use SUBSTR
to solve this problem?
mystring := SUBSTR (full_string, 5, 17); -- start and end? Nah...
mystring := SUBSTR (full_string, 5, 12); -- end – start?
mystring := SUBSTR (full_string, 5, 13); -- end – start + 1?
mystring := SUBSTR (full_string, 5, 11); -- end – start - 1?
Grab everything between the
5th and 17th position
But which of these
does the job?
A Straightforward Abstraction
 Create a “between string” function that works with
starting and ending positions
CREATE OR REPLACE FUNCTION betwnStr (
string_in IN VARCHAR2,
start_in IN INTEGER,
end_in IN INTEGER
)
RETURN VARCHAR2
IS
BEGIN
RETURN (
SUBSTR (
string_in,
start_in,
end_in – start_in + 1
)
);
END;
myString := betwnStr (yourString, 5, 17);
A Truly Crude
Testing Technique
 Let’s see…what should I check for?
SQL> exec DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', 3, 5));
cde
And so on, and so forth...very time consuming, very haphazard...and
what happens when you want to run the tests a second time?
 Oh, and what about this?
SQL> exec DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', 0, 2));
ab
 Here's a good one:
SQL> exec DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', 3, 100));
cdefgh
Slightly Better:
Build a Test Script
 Let’s see…what should I check for?
BEGIN
DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', 3, 5));
DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', 0, 2));
DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', NULL, 5));
DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', 3, NULL));
DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', 3, 100));
DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', -3, -5));
DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', -3, 0));
END;
/
SQL> @betwnstr.tst
cde
ab
cdefgh
fgh
Yielding this
output:
Which tells us
what precisely?
Problems with Typical Testing
 Almost entirely ad hoc
– No comprehensive effort to compile test cases
– No infrastructure to record cases and administer tests
 Difficult to verify correctness
– If you wrote the program you might know that it was supposed
to be “abc” or “abcd”
– But what about somebody who comes along to maintain the
code?
 Reliance on the user community to test
– Since we are never really sure we’ve tested properly, we rely
on our users (or, we are lucky, the QA department) to finish our
job
There has got to be a better way!
How About Extreme Programming?
 "Extreme programming" sounds, well, extreme
– It really isn't
– It takes well-accepted ideas about programming and
takes them to extremes
 Resources on extreme programming:
– www.xprogramming.com
– www.extremeprogramming.org
– Extreme Programming Explained by Kent Beck
– Extreme Programming Installed by Ron Jeffries, et al
– Planning Extreme Programming by Ron Jeffries, et al
Common Sense Taken to
Extremes
 If code reviews are good, we'll review code all the time
(pair programming)
 If testing is good, everybody will test all the time (unit
testing), even the customers (functional testing)
 If design is good, we'll make it a part of everybody's daily
business (refactoring)
 If simplicity is good, we'll always leave the system with
the simplest design that supports its current functionality
(the simplest thing that could possibly work)
A selection of extremes from XP Explained, Beck
Extreme Unit
Testing Principles
 Write unit tests first!
 Code a little, test a lot
 Build automated red light-green light tests
If testing is good, everybody will test all the time
Write Unit Tests First
 What is my program supposed to do?
– By writing the test first, you concentrate more on the interface
than the implementation
 Write unit tests…
– Before you start writing your program
– Before you fix a bug (turn each bug report into a test case)
– To "document" each enhancement request -- then implement
All of string from
starting point.
Positive # greater than
length of string
Positive #
NULLSmaller positive #Positive #
NULLNULLNOT NULL
NULLNULLNULL
ResultEnd ValueStart Value
Code a Little, Test a Lot
 We are all in a hurry to get our coding done, but the
reality is that most of our time is spent on debugging,
not writing code
– We need to develop our code cleaner the "first time"
 Incremental development, coupled with comprehensive
testing, will improve productivity and code quality
simultaneously
– Make small changes, then test
– Add small pieces of functionality, then test
– Constantly add to your test cases for the unit test
Automated, Red Light-Green
Light Tests
 If we are going to build lots of tests and run them often,
we need to be able to run those tests easily
– This includes the setting up and cleaning up of test data and
other elements
– If this process is not automated, developers will not test
 A developer should be able to determine at a glance
whether the code passed its unit tests
– Do not leave it up to the developer to analyze the results to
determine the status of the tests
 This is called the red-light, green-light approach
– Your code does not work until you get a "green light" – 100%
success
Testing the utPLSQL Way
 A unit testing “framework” for PL/SQL
developers
– Set of processes and code that conform to the
Extreme Programming unit testing principles
SQL> exec utplsql.test ('betwnstr')
.
> 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: "betwnstr"
utPLSQL Architecture
 utPLSQL is a fun demonstration of the use of dynamic SQL (really,
dynamic PL/SQL) and packaged data
– utPLSQL.test constructs the names of and executes the setup, unit test
and teardown procedures based on the program name you provide.
– utAssert populates a collection with results (failure) data
ut_Setup
ut_TestMe
ut_Teardown
utPLSQL.test
Test Engine
Your Test Package
Results Array
Test for Nulls
Invalid ID
Valid ID
Start date too late
End date too early
Name unique
Report Results
1
2
3
4
Assert EQ
Assert NULL
Assert EqTable
Assertion API
5
Steps in Using utPLSQL
Step 1. Download and install utPLSQL
Step 2. Choose a program to test and identify the test cases
Step 3. Build a test package that incorporates those test cases
Step 4. Run your test using the utPLSQL engine
Download and Install utPLSQL
 Visit http://oracle.oreilly.com/utplsql
 Unzip, open up the documentation, install the
utPLSQL software base, and you are ready to
test
– Installs in Oracle7, Oracle8 and Oracle8i
– You can create a separate schema to hold utPLSQL
source or install a version for each developer
Choose Program,
Define Test Cases
 You can test stand-alone procedures or packages, test
the entire set of programs in a package or test a subset
of those programs
– Start with a small program to try out the approach.
 Build your grid of input values and expected outputs.
 Once test cases are defined, it is time to translate them
into code...the test package!
Build a Test Package
 Build a test package that
contains a unit test for each
program in your package
 Must conform to the
standard utPLSQL API:
– Public setup and teardown
procedures
– Separate procedures for each
unit test
 Best approach: generate the
starting point of the test
package with the utGen
package
SQL> exec utGen.testpkg ('betwnstr');
CREATE OR REPLACE PACKAGE ut_betwnstr
IS
PROCEDURE ut_setup;
PROCEDURE ut_teardown;
PROCEDURE ut_BETWNSTR;
END ut_betwnstr;
/
CREATE OR REPLACE PACKAGE BODY ut_betwnstr
IS
PROCEDURE ut_setup ... END;
PROCEDURE ut_teardown ... END;
PROCEDURE ut_BETWNSTR IS
BEGIN
utAssert.this (
'Test of BETWNSTR',
BETWNSTR(
STRING_IN => '',
START_IN => '',
END_IN => '')
);
END ut_BETWNSTR;
END ut_betwnstr;
Generate a Test Package
 You can even pass an argument grid directly to
utGen to generate virtually complete unit test
packages.
DECLARE
utc VARCHAR2 (1000)
:=
'betwnstr|normal|abcdefgh;3;5|cde|eq
betwnstr|zero start|abcdefgh;0;2|!SUBSTR(''abcdefgh'',0,2)|eq
betwnstr|null start|abcdefgh;!null;2|null|isnull
betwnstr|null end|abcdefgh;!3;!null|null|isnull';
BEGIN
utgen.testpkg_from_string ('betwnstr',
utc,
output_type_in=> utgen.c_file,
dir_in=> ''d:openoracleutplsqlexamples''
);
END;
One line for
each set of IN
parameters
and expected
result.
Example of Gen'd Test Code
 It can take lots of code
to properly test a
program.
 The more you can
generate, the better.
PROCEDURE ut_BETWNSTR
IS
against_this VARCHAR2(2000);
check_this VARCHAR2(2000);
BEGIN
-- Define "control" operation for "normal"
against_this := SUBSTR ('abcdefg',0,2);
-- Execute test code for "normal"
check_this :=
BETWNSTR (
STRING_IN => 'abcdefgh'
,
START_IN => 0
,
END_IN => 2
);
-- Assert success for "normal"
utAssert.eq (
'normal',
check_this,
against_this
);
...
100% Generation!
Complete Unit Test Proc
 Every unit test
procedure consists of
three main parts (which
are sometimes
collapsed together,
depending on the
simplicity of the code
being tested):
– Set up the control
(which might already be
done with the set up
procedure).
– Run the code to be
tested.
– Compare results using
the utAssert package
PROCEDURE ut_del1
IS
fdbk PLS_INTEGER;
BEGIN
/* Delete that finds no rows. */
EXECUTE IMMEDIATE '
DELETE FROM ut_DEL1
WHERE employee_id = -1';
te_employee.del (
-1, rowcount_out => fdbk);
utassert.eqtable (
'No rows deleted', 'EMPLOYEE',
'ut_DEL1');
EXCEPTION
WHEN OTHERS
THEN
utassert.this (
'DEL1 exception ' || SQLERRM,
SQLCODE = 0
);
END;
Control
Test
Compare
Error Failure
Apply utAssertion Validators
 The utAssert offers a set of pre-defined assertion programs
that test for the condition you specify and record any failures
for later red light-green light reports. You can assert that:
– Two scalars, tables, collections, pipes, files and queries are equal
– A value is NULL or is NOT NULL
– A Boolean expression is TRUE
PROCEDURE ut_BETWNSTR IS
BEGIN
...
utAssert.eq ('Typical valid usage',
BETWNSTR(STRING_IN => 'abcdefg',
START_IN => 3, END_IN => 5),
'cde');
utAssert.eqFile ('Dump book data',
file1, loc1,
file2, loc2);
Set up & Tear Down Test Data
 The ut_setup and ut_teardown procedures manage
any data structures needed to run your tests
– These programs are run automatically before and after
tests procedures are executed.
PROCEDURE ut_teardown IS
BEGIN
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE ut_employee';
EXCEPTION
WHEN OTHERS THEN NULL;
END;
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE ut_DEL1';
EXCEPTION
WHEN OTHERS THEN NULL;
END;
...
This is an
example of a
portion of the
tear-down used
to test a table
encapsulation
package
Run Your Test
 Once you have built your test package, you can
simply "hand it over" to utPLSQL for testing with a
simple one-line call:
 You can also construct test "suites" of multiple
packages to test and then run that suite:
SQL> exec utPLSQL.test ('betwnstr');
SQL> exec utPLSQL.testSuite ('PLVision');
See Your Results Instantly
 You are notified of success or failure
– When there is a failure, you see the descriptions of
failed test cases, plus information about the cause of the failure
SQL> exec utplsql.test ('betwnstr')
.
> FFFFFFF AA III L U U RRRRR EEEEEEE
> F A A I L U U R R E
> F A A I L U U R R E
> F A A I L U U R R E
> FFFF A A I L U U RRRRRR EEEE
> F AAAAAAAA I L U U R R E
> F A A I L U U R R E
> F A A I L U U R R E
> F A A III LLLLLLL UUU R R EEEEEEE
.
FAILURE: "betwnstr"
.
UT_BETWNSTR: Typical valid usage; expected "cde", got "cd"
UT_BETWNSTR: IS NULL: NULL start
UT_BETWNSTR: IS NULL: End smaller than start
Change Your Testing Ways
 utPLSQL can make a dramatic difference in your ability
to test and your confidence in the resulting code
 With utPLSQL, you build a comprehensive "library" of
unit tests as you build your application
– These tests and all their test cases can be passed on to other
developers
– Anyone can now enhance or maintain the code with
confidence. Make your changes and run the tests. If you get
a green light, you're OK!
Challenges to Using utPLSQL
 Build the test packages
– This can be almost as complicated as writing your application
code.
 Set up/change the test process in your group
– It can be very difficult to move from ad-hoc testing to formal
testing.
 Powerful, well-designed GUI interfaces can make a big
difference.
– Quest is currently exploring how to support utPLSQL in its
development tools.

More Related Content

PDF
prohuddle-utPLSQL v3 - Ultimate unit testing framework for Oracle
PPTX
Oracle Unit Testing with utPLSQL
PDF
POUG2019 - Test your PL/SQL - your database will love you
PDF
Unit Testing Oracle PL/SQL Code: utPLSQL, Excel and More
PDF
Ukoug webinar - testing PLSQL APIs with utPLSQL v3
PPTX
Implementing DDD with C#
PDF
Test Driven Development for PLSQL with utPLSQL v3
PDF
TypeScript: coding JavaScript without the pain
prohuddle-utPLSQL v3 - Ultimate unit testing framework for Oracle
Oracle Unit Testing with utPLSQL
POUG2019 - Test your PL/SQL - your database will love you
Unit Testing Oracle PL/SQL Code: utPLSQL, Excel and More
Ukoug webinar - testing PLSQL APIs with utPLSQL v3
Implementing DDD with C#
Test Driven Development for PLSQL with utPLSQL v3
TypeScript: coding JavaScript without the pain

What's hot (20)

PPTX
Moq Presentation
PDF
All About PL/SQL Collections
PPTX
Task parallel library presentation
PPTX
Unit Testing And Mocking
PPTX
SFDC Batch Apex
PPTX
An Introduction to Unit Testing
PDF
Kotlin Coroutines in Practice @ KotlinConf 2018
PPTX
Unit Testing
PDF
MongoDB vs. Postgres Benchmarks
 
PDF
JavaScript Event Loop
PDF
Domain-Driven Design with ASP.NET MVC
PPTX
Synchronization in Selenium WebDriver
PDF
Domain driven design and model driven development
PDF
How to go about testing in React?
PDF
MySQL partitions tutorial
PDF
Clean coding-practices
PDF
Introduction to jest
PPT
Displaying Data from Multiple Tables - Oracle Data Base
PPTX
TDD - Agile
PDF
Single Sign-On for APEX applications based on Kerberos (Important: latest ver...
Moq Presentation
All About PL/SQL Collections
Task parallel library presentation
Unit Testing And Mocking
SFDC Batch Apex
An Introduction to Unit Testing
Kotlin Coroutines in Practice @ KotlinConf 2018
Unit Testing
MongoDB vs. Postgres Benchmarks
 
JavaScript Event Loop
Domain-Driven Design with ASP.NET MVC
Synchronization in Selenium WebDriver
Domain driven design and model driven development
How to go about testing in React?
MySQL partitions tutorial
Clean coding-practices
Introduction to jest
Displaying Data from Multiple Tables - Oracle Data Base
TDD - Agile
Single Sign-On for APEX applications based on Kerberos (Important: latest ver...
Ad

Similar to utPLSQL: Unit Testing for Oracle PL/SQL (20)

PDF
PL/SQL unit testing with Ruby
PDF
Bgoug 2019.11 test your pl sql - not your patience
PDF
POUG Meetup 1st MArch 2019 - utPLSQL v3 - Testing Framework for PL/SQL
PDF
Agile db testing_techniques
PDF
PL/SQL Unit Testing Can Be Fun
PDF
PL/SQL Unit Testing Can Be Fun!
PPTX
Database Unit Testing Made Easy with VSTS
PDF
SELJE_Database_Unit_Testing_Slides.pdf
PPT
A testing framework for Microsoft SQL-Server
PPTX
#DOAW16 - DevOps@work Roma 2016 - Testing your databases
PDF
utplsql.pdf
PDF
Six simple steps to unit testing happiness
PPTX
Get Testing with tSQLt - SQL In The City Workshop 2014
PDF
SELJE_Database_Unit_Testing.pdf
PPTX
Test your PL/SQL with utPLSQL
PDF
David Parnas - Documentation Based Software Testing - SoftTest Ireland
PPS
Why unit testingl
PPS
Why Unit Testingl
PPS
Why Unit Testingl
PDF
Database development unit test with tSQLt
PL/SQL unit testing with Ruby
Bgoug 2019.11 test your pl sql - not your patience
POUG Meetup 1st MArch 2019 - utPLSQL v3 - Testing Framework for PL/SQL
Agile db testing_techniques
PL/SQL Unit Testing Can Be Fun
PL/SQL Unit Testing Can Be Fun!
Database Unit Testing Made Easy with VSTS
SELJE_Database_Unit_Testing_Slides.pdf
A testing framework for Microsoft SQL-Server
#DOAW16 - DevOps@work Roma 2016 - Testing your databases
utplsql.pdf
Six simple steps to unit testing happiness
Get Testing with tSQLt - SQL In The City Workshop 2014
SELJE_Database_Unit_Testing.pdf
Test your PL/SQL with utPLSQL
David Parnas - Documentation Based Software Testing - SoftTest Ireland
Why unit testingl
Why Unit Testingl
Why Unit Testingl
Database development unit test with tSQLt
Ad

More from Steven Feuerstein (17)

PDF
New(er) Stuff in PL/SQL
PDF
Speakers at Nov 2019 PL/SQL Office Hours session
PDF
New Stuff in the Oracle PL/SQL Language
PDF
AskTOM Office Hours on Database Triggers
PDF
PL/SQL Guilty Pleasures
PDF
Oracle Application Express and PL/SQL: a world-class combo
PDF
Error Management Features of PL/SQL
PDF
JSON and PL/SQL: A Match Made in Database
PDF
OLD APEX and PL/SQL
PDF
High Performance PL/SQL
PDF
Oracle PL/SQL 12c and 18c New Features + RADstack + Community Sites
PDF
AskTOM Office Hours - Dynamic SQL in PL/SQL
PPT
Database Developers: the most important developers on earth?
PDF
Impact Analysis with PL/Scope
PPTX
The Amazing and Elegant PL/SQL Function Result Cache
PPTX
Turbocharge SQL Performance in PL/SQL with Bulk Processing
PPTX
Take Full Advantage of the Oracle PL/SQL Compiler
New(er) Stuff in PL/SQL
Speakers at Nov 2019 PL/SQL Office Hours session
New Stuff in the Oracle PL/SQL Language
AskTOM Office Hours on Database Triggers
PL/SQL Guilty Pleasures
Oracle Application Express and PL/SQL: a world-class combo
Error Management Features of PL/SQL
JSON and PL/SQL: A Match Made in Database
OLD APEX and PL/SQL
High Performance PL/SQL
Oracle PL/SQL 12c and 18c New Features + RADstack + Community Sites
AskTOM Office Hours - Dynamic SQL in PL/SQL
Database Developers: the most important developers on earth?
Impact Analysis with PL/Scope
The Amazing and Elegant PL/SQL Function Result Cache
Turbocharge SQL Performance in PL/SQL with Bulk Processing
Take Full Advantage of the Oracle PL/SQL Compiler

Recently uploaded (20)

PDF
The influence of sentiment analysis in enhancing early warning system model f...
PDF
Produktkatalog für HOBO Datenlogger, Wetterstationen, Sensoren, Software und ...
PDF
sbt 2.0: go big (Scala Days 2025 edition)
PPTX
The various Industrial Revolutions .pptx
PDF
Architecture types and enterprise applications.pdf
PDF
Statistics on Ai - sourced from AIPRM.pdf
PDF
NewMind AI Weekly Chronicles – August ’25 Week III
PDF
How IoT Sensor Integration in 2025 is Transforming Industries Worldwide
PDF
OpenACC and Open Hackathons Monthly Highlights July 2025
PDF
A contest of sentiment analysis: k-nearest neighbor versus neural network
PDF
Enhancing plagiarism detection using data pre-processing and machine learning...
PDF
Flame analysis and combustion estimation using large language and vision assi...
PDF
Accessing-Finance-in-Jordan-MENA 2024 2025.pdf
PPT
What is a Computer? Input Devices /output devices
PPTX
GROUP4NURSINGINFORMATICSREPORT-2 PRESENTATION
PPTX
Modernising the Digital Integration Hub
PPTX
Microsoft Excel 365/2024 Beginner's training
PPTX
MicrosoftCybserSecurityReferenceArchitecture-April-2025.pptx
PPT
Geologic Time for studying geology for geologist
PDF
Hybrid horned lizard optimization algorithm-aquila optimizer for DC motor
The influence of sentiment analysis in enhancing early warning system model f...
Produktkatalog für HOBO Datenlogger, Wetterstationen, Sensoren, Software und ...
sbt 2.0: go big (Scala Days 2025 edition)
The various Industrial Revolutions .pptx
Architecture types and enterprise applications.pdf
Statistics on Ai - sourced from AIPRM.pdf
NewMind AI Weekly Chronicles – August ’25 Week III
How IoT Sensor Integration in 2025 is Transforming Industries Worldwide
OpenACC and Open Hackathons Monthly Highlights July 2025
A contest of sentiment analysis: k-nearest neighbor versus neural network
Enhancing plagiarism detection using data pre-processing and machine learning...
Flame analysis and combustion estimation using large language and vision assi...
Accessing-Finance-in-Jordan-MENA 2024 2025.pdf
What is a Computer? Input Devices /output devices
GROUP4NURSINGINFORMATICSREPORT-2 PRESENTATION
Modernising the Digital Integration Hub
Microsoft Excel 365/2024 Beginner's training
MicrosoftCybserSecurityReferenceArchitecture-April-2025.pptx
Geologic Time for studying geology for geologist
Hybrid horned lizard optimization algorithm-aquila optimizer for DC motor

utPLSQL: Unit Testing for Oracle PL/SQL

  • 1. utPLSQL A Unit Testing Framework for Oracle PL/SQL Code Achieving PL/SQL Excellence Steven Feuerstein Original creator of utPLSQL, not currently active on project (2016) Visit the Github Repo for utPLSQL: http://https://github.com/utPLSQL
  • 2. Aw, Gee, Mom, do I have to test my code? Only if you want:  Successful applications – That is the whole point, after all.  Successful applications on time – "We don't have time to test"? Hah! Solid testing improves the chances of putting out quality code on time.  Developer and user confidence – It's a wonderful feeling to know that our code really and truly works. – Our users then love us and support us.
  • 3. Different Kinds of Tests  Functional, System, Integration tests – Written by the software customer, it answers the question “What do I need to verify before I am confident this feature works?”  Many other types of tests – Stress tests – real-world workload testing – Monkey tests – tests responses to unusual conditions – Parallel tests – compares behavior of new and old systems  And then there are unit tests... – Written by the developer, they test individual units (procedure or function in PL/SQL) The focus in this presentation.
  • 4. Wouldn't it be great if...  It was easy to construct tests – An agreed-upon and effective approach to test construction that everyone can understand and follow  It was easy to run tests – And see the results, instantly and automatically.  Testing were completely integrated into my development, QA and maintenance processes – No program goes to QA until it has passed a battery of tests – Anyone can maintain with confidence, because my test suite automatically validates my changes
  • 5. POLL  How do you (or your team) unit test your PL/SQL code today?  Possible answers: – Everyone does their own thing and we hope for the best. – Our users test our code. – We have a formal test process – We use automated testing software
  • 6. Typical Development and Testing Scenario  Let's walk through a typical development/test flow, critique it, and then take a look at how you might do the same thing with utPLSQL  We'll use a very simple example: – building an improvement to the SUBSTR function
  • 7. Improving upon SUBSTR  SUBSTR returns the sub-string specified by start position and number of characters. just10 := SUBSTR (full_string, 3, 10); Grab 10 characters staring from 3rd position  Suppose I have the starting and ending positions (or even sub- strings). How do I use SUBSTR to solve this problem? mystring := SUBSTR (full_string, 5, 17); -- start and end? Nah... mystring := SUBSTR (full_string, 5, 12); -- end – start? mystring := SUBSTR (full_string, 5, 13); -- end – start + 1? mystring := SUBSTR (full_string, 5, 11); -- end – start - 1? Grab everything between the 5th and 17th position But which of these does the job?
  • 8. A Straightforward Abstraction  Create a “between string” function that works with starting and ending positions CREATE OR REPLACE FUNCTION betwnStr ( string_in IN VARCHAR2, start_in IN INTEGER, end_in IN INTEGER ) RETURN VARCHAR2 IS BEGIN RETURN ( SUBSTR ( string_in, start_in, end_in – start_in + 1 ) ); END; myString := betwnStr (yourString, 5, 17);
  • 9. A Truly Crude Testing Technique  Let’s see…what should I check for? SQL> exec DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', 3, 5)); cde And so on, and so forth...very time consuming, very haphazard...and what happens when you want to run the tests a second time?  Oh, and what about this? SQL> exec DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', 0, 2)); ab  Here's a good one: SQL> exec DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', 3, 100)); cdefgh
  • 10. Slightly Better: Build a Test Script  Let’s see…what should I check for? BEGIN DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', 3, 5)); DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', 0, 2)); DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', NULL, 5)); DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', 3, NULL)); DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', 3, 100)); DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', -3, -5)); DBMS_OUTPUT.PUT_LINE (betwnstr ('abcdefgh', -3, 0)); END; / SQL> @betwnstr.tst cde ab cdefgh fgh Yielding this output: Which tells us what precisely?
  • 11. Problems with Typical Testing  Almost entirely ad hoc – No comprehensive effort to compile test cases – No infrastructure to record cases and administer tests  Difficult to verify correctness – If you wrote the program you might know that it was supposed to be “abc” or “abcd” – But what about somebody who comes along to maintain the code?  Reliance on the user community to test – Since we are never really sure we’ve tested properly, we rely on our users (or, we are lucky, the QA department) to finish our job There has got to be a better way!
  • 12. How About Extreme Programming?  "Extreme programming" sounds, well, extreme – It really isn't – It takes well-accepted ideas about programming and takes them to extremes  Resources on extreme programming: – www.xprogramming.com – www.extremeprogramming.org – Extreme Programming Explained by Kent Beck – Extreme Programming Installed by Ron Jeffries, et al – Planning Extreme Programming by Ron Jeffries, et al
  • 13. Common Sense Taken to Extremes  If code reviews are good, we'll review code all the time (pair programming)  If testing is good, everybody will test all the time (unit testing), even the customers (functional testing)  If design is good, we'll make it a part of everybody's daily business (refactoring)  If simplicity is good, we'll always leave the system with the simplest design that supports its current functionality (the simplest thing that could possibly work) A selection of extremes from XP Explained, Beck
  • 14. Extreme Unit Testing Principles  Write unit tests first!  Code a little, test a lot  Build automated red light-green light tests If testing is good, everybody will test all the time
  • 15. Write Unit Tests First  What is my program supposed to do? – By writing the test first, you concentrate more on the interface than the implementation  Write unit tests… – Before you start writing your program – Before you fix a bug (turn each bug report into a test case) – To "document" each enhancement request -- then implement All of string from starting point. Positive # greater than length of string Positive # NULLSmaller positive #Positive # NULLNULLNOT NULL NULLNULLNULL ResultEnd ValueStart Value
  • 16. Code a Little, Test a Lot  We are all in a hurry to get our coding done, but the reality is that most of our time is spent on debugging, not writing code – We need to develop our code cleaner the "first time"  Incremental development, coupled with comprehensive testing, will improve productivity and code quality simultaneously – Make small changes, then test – Add small pieces of functionality, then test – Constantly add to your test cases for the unit test
  • 17. Automated, Red Light-Green Light Tests  If we are going to build lots of tests and run them often, we need to be able to run those tests easily – This includes the setting up and cleaning up of test data and other elements – If this process is not automated, developers will not test  A developer should be able to determine at a glance whether the code passed its unit tests – Do not leave it up to the developer to analyze the results to determine the status of the tests  This is called the red-light, green-light approach – Your code does not work until you get a "green light" – 100% success
  • 18. Testing the utPLSQL Way  A unit testing “framework” for PL/SQL developers – Set of processes and code that conform to the Extreme Programming unit testing principles SQL> exec utplsql.test ('betwnstr') . > 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: "betwnstr"
  • 19. utPLSQL Architecture  utPLSQL is a fun demonstration of the use of dynamic SQL (really, dynamic PL/SQL) and packaged data – utPLSQL.test constructs the names of and executes the setup, unit test and teardown procedures based on the program name you provide. – utAssert populates a collection with results (failure) data ut_Setup ut_TestMe ut_Teardown utPLSQL.test Test Engine Your Test Package Results Array Test for Nulls Invalid ID Valid ID Start date too late End date too early Name unique Report Results 1 2 3 4 Assert EQ Assert NULL Assert EqTable Assertion API 5
  • 20. Steps in Using utPLSQL Step 1. Download and install utPLSQL Step 2. Choose a program to test and identify the test cases Step 3. Build a test package that incorporates those test cases Step 4. Run your test using the utPLSQL engine
  • 21. Download and Install utPLSQL  Visit http://oracle.oreilly.com/utplsql  Unzip, open up the documentation, install the utPLSQL software base, and you are ready to test – Installs in Oracle7, Oracle8 and Oracle8i – You can create a separate schema to hold utPLSQL source or install a version for each developer
  • 22. Choose Program, Define Test Cases  You can test stand-alone procedures or packages, test the entire set of programs in a package or test a subset of those programs – Start with a small program to try out the approach.  Build your grid of input values and expected outputs.  Once test cases are defined, it is time to translate them into code...the test package!
  • 23. Build a Test Package  Build a test package that contains a unit test for each program in your package  Must conform to the standard utPLSQL API: – Public setup and teardown procedures – Separate procedures for each unit test  Best approach: generate the starting point of the test package with the utGen package SQL> exec utGen.testpkg ('betwnstr'); CREATE OR REPLACE PACKAGE ut_betwnstr IS PROCEDURE ut_setup; PROCEDURE ut_teardown; PROCEDURE ut_BETWNSTR; END ut_betwnstr; / CREATE OR REPLACE PACKAGE BODY ut_betwnstr IS PROCEDURE ut_setup ... END; PROCEDURE ut_teardown ... END; PROCEDURE ut_BETWNSTR IS BEGIN utAssert.this ( 'Test of BETWNSTR', BETWNSTR( STRING_IN => '', START_IN => '', END_IN => '') ); END ut_BETWNSTR; END ut_betwnstr;
  • 24. Generate a Test Package  You can even pass an argument grid directly to utGen to generate virtually complete unit test packages. DECLARE utc VARCHAR2 (1000) := 'betwnstr|normal|abcdefgh;3;5|cde|eq betwnstr|zero start|abcdefgh;0;2|!SUBSTR(''abcdefgh'',0,2)|eq betwnstr|null start|abcdefgh;!null;2|null|isnull betwnstr|null end|abcdefgh;!3;!null|null|isnull'; BEGIN utgen.testpkg_from_string ('betwnstr', utc, output_type_in=> utgen.c_file, dir_in=> ''d:openoracleutplsqlexamples'' ); END; One line for each set of IN parameters and expected result.
  • 25. Example of Gen'd Test Code  It can take lots of code to properly test a program.  The more you can generate, the better. PROCEDURE ut_BETWNSTR IS against_this VARCHAR2(2000); check_this VARCHAR2(2000); BEGIN -- Define "control" operation for "normal" against_this := SUBSTR ('abcdefg',0,2); -- Execute test code for "normal" check_this := BETWNSTR ( STRING_IN => 'abcdefgh' , START_IN => 0 , END_IN => 2 ); -- Assert success for "normal" utAssert.eq ( 'normal', check_this, against_this ); ... 100% Generation!
  • 26. Complete Unit Test Proc  Every unit test procedure consists of three main parts (which are sometimes collapsed together, depending on the simplicity of the code being tested): – Set up the control (which might already be done with the set up procedure). – Run the code to be tested. – Compare results using the utAssert package PROCEDURE ut_del1 IS fdbk PLS_INTEGER; BEGIN /* Delete that finds no rows. */ EXECUTE IMMEDIATE ' DELETE FROM ut_DEL1 WHERE employee_id = -1'; te_employee.del ( -1, rowcount_out => fdbk); utassert.eqtable ( 'No rows deleted', 'EMPLOYEE', 'ut_DEL1'); EXCEPTION WHEN OTHERS THEN utassert.this ( 'DEL1 exception ' || SQLERRM, SQLCODE = 0 ); END; Control Test Compare Error Failure
  • 27. Apply utAssertion Validators  The utAssert offers a set of pre-defined assertion programs that test for the condition you specify and record any failures for later red light-green light reports. You can assert that: – Two scalars, tables, collections, pipes, files and queries are equal – A value is NULL or is NOT NULL – A Boolean expression is TRUE PROCEDURE ut_BETWNSTR IS BEGIN ... utAssert.eq ('Typical valid usage', BETWNSTR(STRING_IN => 'abcdefg', START_IN => 3, END_IN => 5), 'cde'); utAssert.eqFile ('Dump book data', file1, loc1, file2, loc2);
  • 28. Set up & Tear Down Test Data  The ut_setup and ut_teardown procedures manage any data structures needed to run your tests – These programs are run automatically before and after tests procedures are executed. PROCEDURE ut_teardown IS BEGIN BEGIN EXECUTE IMMEDIATE 'DROP TABLE ut_employee'; EXCEPTION WHEN OTHERS THEN NULL; END; BEGIN EXECUTE IMMEDIATE 'DROP TABLE ut_DEL1'; EXCEPTION WHEN OTHERS THEN NULL; END; ... This is an example of a portion of the tear-down used to test a table encapsulation package
  • 29. Run Your Test  Once you have built your test package, you can simply "hand it over" to utPLSQL for testing with a simple one-line call:  You can also construct test "suites" of multiple packages to test and then run that suite: SQL> exec utPLSQL.test ('betwnstr'); SQL> exec utPLSQL.testSuite ('PLVision');
  • 30. See Your Results Instantly  You are notified of success or failure – When there is a failure, you see the descriptions of failed test cases, plus information about the cause of the failure SQL> exec utplsql.test ('betwnstr') . > FFFFFFF AA III L U U RRRRR EEEEEEE > F A A I L U U R R E > F A A I L U U R R E > F A A I L U U R R E > FFFF A A I L U U RRRRRR EEEE > F AAAAAAAA I L U U R R E > F A A I L U U R R E > F A A I L U U R R E > F A A III LLLLLLL UUU R R EEEEEEE . FAILURE: "betwnstr" . UT_BETWNSTR: Typical valid usage; expected "cde", got "cd" UT_BETWNSTR: IS NULL: NULL start UT_BETWNSTR: IS NULL: End smaller than start
  • 31. Change Your Testing Ways  utPLSQL can make a dramatic difference in your ability to test and your confidence in the resulting code  With utPLSQL, you build a comprehensive "library" of unit tests as you build your application – These tests and all their test cases can be passed on to other developers – Anyone can now enhance or maintain the code with confidence. Make your changes and run the tests. If you get a green light, you're OK!
  • 32. Challenges to Using utPLSQL  Build the test packages – This can be almost as complicated as writing your application code.  Set up/change the test process in your group – It can be very difficult to move from ad-hoc testing to formal testing.  Powerful, well-designed GUI interfaces can make a big difference. – Quest is currently exploring how to support utPLSQL in its development tools.