SlideShare a Scribd company logo
DECEMBER 2003 ■ 5
ODTUG TECHNICAL JOURNAL
Do You Test Your PL/SQL?
Everyone thinks they test their code, but how robust is
your PL/SQL testing? Does the following dialog sound at
all familiar?
If I ask: “Do You Test Your PL/SQL?” what is your answer?
“Of course we do! Everybody tests their code don’t they?
Since it works, it must have been tested.”
Then you have documented test plans?
“Well....”
And you have plans for all testing types: unit test, stress
testing, system tests, regression tests...
“Uh....”
And of course your testing is automated and repeatable.
“Well, what I mean is that we unit test our PL/SQL.”
So your unit tests are repeatable, and can be run by
any developer.
“We have the programmer unit test his own code,
it’s easier...”
And the testing is automated of course.
“Well, I think they use SQL scripts...”
Of course, how to use the scripts and the purpose of each
test case is documented.
“OK, OK, I see your point. But the code works, since it
passed the system test!”
OK, so let’s be honest, what testing do you really do?
“Well, the programmer
tests it a bit, and
when he is happy we
integrate it. If it does
not crash the system
and seems to do what
it is supposed to do
we’re happy. Oh, and
we do have the team
lead review the code...”
Of course, you probably
have better testing practices
than this scenario, but
everyone can probably
enhance their testing!
What is
Unit Testing?
Unit testing is only
one of the types of testing
that a system will undergo
during the system develop-
ment process, but it is an
important one!
TYPES OF TESTING
Table 1 is a list of some of the standard testing that might
be done during system development.
You may not quite agree with these definitions, or you may
give these test slightly different names. However, most systems
undergo various levels of tests that should fit within this
spectrum. This article is going to focus on unit testing.
UNIT TESTING
Here is a list of some of the features of unit testing:
• Testing of individual program units
• Usually done by the person who programs the code
• However, can be done by someone else on the
development team
• Does NOT test the program unit in the context of the
entire system
• In PL/SQL, this usually will be done for procedures
and functions
Basically, unit testing is the testing that a programmer
does on a specific program unit they have written. It’s often
considered to be simply part of the development effort.
TestYour PL/SQL BeforeYou Write It!
— Ken Atkins
Creative Design Associates
ODTUG
MEMBER
Award Winner
ODTUG 2003
EDITOR’S CHOICE
Continued
Acceptance Test
System Test
Integration Test
Stress Test
Regression Test
Unit Test
Overall system testing that is done to prove that the system meets the
requirements. Does not necessarily test every bit of functionality,
but will test overall system functionality.
Test the entire system to ensure that every component works
correctly as it is built. The test is performed on the entire
configuration/build that will be delivered. The system test
is usually a complete test that will test every component.
Performed on a specific program unit or subsystem to ensure that it
integrates with other components of the system.
Test of certain program units or subsystems for multiple users or
processes to ensure that the system performs efficiently under high
transaction volume.
Overall system testing that is done to prove that the system still
works correctly after changes. Usually done during system patches
or upgrades, database upgrades, or dependent system upgrades, even
if the system being tested does not change.
Testing of specific program unit to ensure that it works as specified.
The unit test is done as a standalone test of the program unit without
any dependency or interaction with other program units.
Test Type Description
Table 1. Standard Test Descriptions
ODTUG TECHNICAL JOURNAL
6 ■ DECEMBER 2003
Test Your PL/SQL Before You Write It! (Continued)
Why Perform “Formal” Unit Testing?
There are many reasons why you should consider
performing “formal” unit testing:
• To develop code that actually works! If you don’t
actually think about and plan your testing, there will
be no guarantee that the code will work correctly.
• To ensure code works any way it is used. If you use
good design practices and build your code in a very
modular fashion, you will often end up with generic
modular programs that can be used in many ways
throughout your application. When you first build and
integrate these modules, you will make sure they work
correctly the way they are initially used. However,
unless you plan specific unit tests you may not make
sure that they work correctly when used in other ways.
These same program units may be used later in the
development process in a fashion that was not fully
tested during the initial development. This leaves your
system open for defects to be easily introduced later.
• To ensure that code meets design requirements.
A good unit test will prove that a program meets its
design requirements. It can also codify and clarify
those requirements so that there is less confusion and
error in the design implementation. Often during the
development of the unit tests, the developer will find
out that they misunderstood the requirements or they
will find errors in the design.
• To deliver applications on time! This might sound
counter-intuitive since a robust implementation of
formal unit tests such as I am proposing will seem to
add to the program unit development time. I often hear
people say that they don’t have time to do this sort of
unit testing. In my opinion, this perception is incorrect.
All of the work you need to do to implement good unit
tests has to be done anyway. The developer still has to
spend time understanding the program’s requirements.
He still has to perform some sort of testing. And if he
produces poorly tested code, he will have to spend a lot
of time debugging problems uncovered during system
testing or integration.
• To develop code that can be shared. If a program
unit is robust and thoroughly tested, it is much more
likely that someone else on the development team
will be able to use it instead of redeveloping the same
functionality. Also, producing the unit test makes
the developer think through the call interface,
and the developer will invariably come up with a
better call interface with more parameters if they
think through the unit testing needed. I have also
found that if code functions poorly, or is not designed
correctly, it will not be used by other developers even
when it should. The other developers will simply write
their own code instead of using someone else’s poorly
implemented code.
Why Automate Unit Tests?
There are many reasons why unit tests should be
automated. (Obviously, they can’t be 100 percent automated,
someone has to at least push the button!) Here are some
of the reasons:
• To ensure that unit tests are 100 percent
repeatable. If your unit tests are automated, you
will always know that the program unit is tested the
same way, and with the same parameters. If these
tests are not automated, then the quality of the testing
is left to the whim of the person doing the testing.
• Automation makes it easy to repeat tests when
conditions change. If the testing is automated, then
you can easily repeat the tests whenever something
changes that might affect your system. Some examples
of the changes where your system might benefit from a
repeat of the unit tests are:
° Upgrade in database version
° Changes to your data model
° New versions of utilities or dependent systems
• Automation allows any team member to perform
tests. If the unit tests are ad-hoc, only the program
unit developer will be able to easily and thoroughly
test the program. If the unit tests are automated, you
can easily have any member of your team perform
the test and get thorough testing. If someone has to
make a change to the code, they will only need to learn
enough of the code to make the specified change. The
automated unit test should ensure that the rest of the
code continues to function as designed.
• To save time (in the long run!). Initially, there is a
lot of effort involved in automating the unit tests. The
first time you perform your unit tests it will take much
longer to automate them than to simply perform ad-hoc
tests. However, when you rerun the tests later during
your system development process you will benefit from
the initial work.
Why Don’t People Automate Unit Tests?
There are many reasons that automated unit testing
is not more common in PL/SQL development projects.
The most common reason is probably: “We don’t have time!”
Many times the project timeline is too tight to easily allow
for very robust automated unit tests. Other people think
that it is just too much work for not enough benefit (I hope to
convince you otherwise!). Sometimes I think that the real
reason is that writing the unit tests is just too boring! You may
think I am being facetious about this, but I’m not. All too often
the real reason that decisions are made have more to do with
the preferences of the development team than any real
business justification.
There are always enough excuses given for why our
practices do not produce the best results. What we should be
looking for are reasons to implement practices that improve
our code in a consistent fashion. I hope this article may help
convince you that it is beneficial to write automated unit test
scripts to test your PL/SQL.
ODTUG TECHNICAL JOURNAL
Typical Unit Testing Scenario
Let’s compare this “nirvana” to a “typical” unit testing
scenario, and see how close it is to the goals above. We will
start with a very simple example: A function to multiply a
number by a percentage. Listing 1 is the example code.
This example is kept simple on purpose so that we can
focus on the unit testing technique, not on the example. Also,
don’t say anything about the weird algorithm; it is used on
purpose (you’ll see why later).
You might use this function like this:
v_RetValue := salary_mult(v_InValue, 10);
Ad-Hoc testing
OK, now let’s test it. What should I test for?
How about this:
SQL> EXEC DBMS_OUTPUT.PUT_LINE
(salary_mult(1234, 10) );
1357
Let’s try another test:
SQL> EXEC DBMS_OUTPUT.PUT_LINE
(salary_mult(0, 10) );
0
Or one more:
SQL> EXEC DBMS_OUTPUT.PUT_LINE
(salary_mult(1234, -10) );
1111
OK, that’s all I can think of.... I guess it works.
PUTTING IT INTO A SCRIPT
A better approach might be to put the tests into a SQL
script (see Listing 2).
Now you can run all of the tests with one command, shown
in Listing 3.
But what do these results mean? Did the
test pass or fail? You can’t easily tell from
the results.
WHAT IS WRONG WITH THE
AD-HOC APPROACH?
There are many problems with this
“ad-hoc” approach to unit testing:
• The testing is not very thorough
• There is no standardization of the
unit tests
• No easy way to record results
• Interpretation of test results relies
on knowledge of tester
• More work for maintenance
programmers since they have to
learn how to test the code
• You are actually letting your
users test the code!
How can we do better?
Write Automated Formal Unit Tests
Before Writing the Code!
One way to do a much better job in this area is to
write your unit tests before you actually write the code!
This approach has a lot of advantages, as you will see.
This idea is one of the practices associated with Extreme
Programming (XP).
ABOUT XP (EXTREME PROGRAMMING)
Extreme Programming (or XP) takes standard, common
sense, well-accepted programming practices and... takes them
to the extreme! For example, in Extreme Programming:
• Peer review of your code (a standard practice) —
becomes Pair Programming
• Seeking customer input for requirements—becomes
Customer expert on development team
• Everyone’s code should work together —becomes
Integrate often (i.e., daily)
• And your code should be tested—becomes Write unit
tests BEFORE writing the code!
WHY WRITE UNIT TESTS BEFORE THE CODE?
Why would you want to write the unit tests before writing
the code? After all, you don’t even have anything to test yet!
There are many reasons this approach will lead to better, more
supportable code with less defects.
• Leads to better design of program unit. Writing the
unit test before writing the code leads to better design of
the program unit. The programmer will have to really
think through the call interface in order to write the
unit tests, and this will often uncover problems with the
initial design that can be remedied before the code is
actually written.
Listing 2. Testing with an SQL Script
Listing 3. Executing the SQL Test Script
Listing 1. Simple PL/SQL Program to Be Tested
DECEMBER 2003 ■ 7
Continued
8 ■ DECEMBER 2003 ODTUG TECHNICAL JOURNAL
Test Your PL/SQL Before You Write It! (Continued)
• Forces developer to think about the interface
before the algorithm. This will lead to code that
is more easily reused by other team members. For
example, you might uncover the need for additional
parameters. This approach also leads to the parameters
being defined in a way that is easy to understand
and use.
• Encourages developers to think modularly.
Creating unit tests for large monolithic programs
can be very difficult! It is much easier to create
the unit tests for small program units that do
only one thing. Therefore, this unit test approach
often leads to the developers creating more
modular code. More modular code can help increase
code reusability.
• You can tell when a program is done! How do you
know when you are finished writing a program? You
could say that when you feel you have met all of the
requirements, then the program is done. But how
do you prove you have met all of the requirements?
Maybe when the code is system-tested? Otherwise it’s
just the developer’s opinion. Also, how can you measure
partial completion? How often does code get stuck
in the permanent 90 percent done status? Using
the unit test first approach, you know when the code
is done....it is done when it passes the unit tests! If you
set up the right environment, you can use this fact
to get a complete and accurate picture of how close to
completion a system is (at least after the unit tests have
been written!).
WHEN SHOULD YOU WRITE UNIT TESTS?
There are a few different times in the program unit’s life
cycle where you would want to write or add to its unit tests.
Here are some of them:
• Write unit tests before you write any code.
To take advantage of this approach, you should write
the unit tests before you actually write the code.
Ideally, you should write ALL of the unit test programs
before writing any code. However, for complicated
systems this might not be possible. Often you will have
to write some of the code before you can even write unit
tests for other parts of the code. Also, you may not be
able to even design parts of the system until you have
written other parts of the system. However, you should
get as close as possible.
• Write another unit test before you fix each bug.
You should also write another unit test case before
you fix each bug. This test case will be used to prove
you have actually fixed the bug, and to ensure that
the bug remains fixed. How many times have you
fixed a bug only to have it crop up again for some
reason? Adding a test case for each bug ensures that
the bug remains fixed even when other aspects of the
system change.
• Write unit tests before making any enhancements.
Each enhancement will also start with a new unit
test or additional unit test cases. These will be used
to ensure that the enhancement was done correctly.
Writing the unit tests first will also ensure that the
programmer really understands the enhancement
before he starts to code it. How often have you
coded an enhancement only to find that what you
coded was not what they wanted? Another advantage
of writing the unit tests is that they become de facto
documentation for the functionality requested in
the enhancement.
But That’s A Lot of Work!
You bet it is! Developing high quality systems is not easy.
In this approach, you code a little and test a lot. In fact, coding
the unit test will often take more time than actually coding
the program unit. This is especially true for smaller utility
programs. Of course you get the most benefit from these types
of programs because many other programs often use them and
you want them to be bulletproof.
ACTUALLY, IT WILL SAVE WORK IN
THE LONG RUN
In my opinion, this approach will actually save work
in the long run. This is because the fewer bugs you have
to fix, and the earlier you catch them in the process, the
cheaper they are to fix. Detecting and fixing a bug during
the build phase is orders of magnitude cheaper than
discovering a bug in your production system. If used
consistently and correctly this approach can lead
to systems where the only bugs are due to design or
analysis errors, not programming bugs. Your code
will work right the first time!
AUTOMATE AND STANDARDIZE AS MUCH
AS POSSIBLE
One way to reduce the amount of work this approach
takes is to automate the process as much as possible.
Automation will save your developers time in the development
and execution of the unit tests. It will also ensure that all
of your developers will be using the same unit test approach.
Good unit test automation will also make it easy to perform
the tests and see the results.
Wouldn’t it Be Great If...
OK, so far I have been making a case for creating format
automated unit tests for your PL/SQL code. But how do you go
about doing this? Wouldn’t it be great if:
• Everyone on the project used the same unit
test approach
ODTUG TECHNICAL JOURNAL
• It was fairly easy to construct unit tests in a
consistent fashion
• It was easy to run the unit tests and see the results
• All of the unit tests could be grouped together into a unit
test suite
• Automated unit testing was simply a part of your
development cycle
• No program goes to QA without passing a formal
unit test
utPLSQL to the Rescue!
Fortunately, there is a way to easily achieve many of
the benefits I have been extolling! The utPLSQL package
is an open source unit testing framework that is available
for use with PL/SQL unit testing. It was originally developed
and championed by Steven Feuerstein, the PL/SQL guru
(author of many great books about PL/SQL). The framework
is based on a standard Extreme Programming (XP) idea.
It is modeled after some other XP unit testing frameworks,
specifically Junit and Xunit.
Now that I’ve convinced you of the value of this
approach (I hope), the rest of this discussion will focus
on a specific example of using utPLSQL to write and
execute unit tests.
EXAMPLE OF UTPLSQL RESULT
Let’s start with an example of using utPLSQL.
Example 1 shows a successful test.
This example shows that the EMPDEPT package
successfully passed the unit tests. The details of each test
are shown (most of the test cases were removed from the
output for this example).
The utPLSQL Architecture
Here is an overview of the utPLSQL architecture.
It may seem rather complicated, but when you start
using it you will see that it’s really
not too bad. I will summarize the
unit test development process using
utPLSQL. Refer to Figure 1 for a
diagram of the following steps.
1. Programmer writes UT
package. In order to automate
the unit tests, you will have to
write them in PL/SQL. Usually
you will create one unit test
package for each PL/SQL package.
This unit test package will have
to conform to the standards
dictated by the utPLSQL
architecture. For example there
has to be a setup and a teardown
procedure in the package.
2. Programmer executes utPLSQL.test. When the
unit test package is finished, the programmer (or other
tester) will call the test procedure in the utPLSQL
package to actually perform the tests. The name of the
package to be tested is passed as a parameter.
3. utPLSQL.test calls code in UT package. The unit
test package for the specified package will be called by
utPLSQL. The unit test package is always named the
same as the package it tests with a “UT_” prefix.
4. Setup (and later teardown) data for test. The
UT_Setup procedure in your UT package is called
first by utPLSQL. This procedure performs any setup
tasks needed to perform all of the unit tests in the
package. This includes creating test data, storing
expected results in PL/SQL tables, setting up package
states, anything you need to do to perform the tests.
5. The UT package calls your actual code. Next,
utPLSQL will call your actual code. Each procedure
or function in your package for which you want to
perform unit tests will have a procedure in this
package. Then utPLSQL reads the UT package spec
and automatically calls all of the unit test procedures
you have defined.
Continued
Example 1. Successful Test Using utPLSQL
DECEMBER 2003 ■ 9
Figure 1. The utPLSQL Architecture
ODTUG TECHNICAL JOURNAL
10 ■ DECEMBER 2003
Test Your PL/SQL Before You Write It! (Continued)
6. The UT package Asserts the tests using the
utPLSQL assert API. Each of the unit test procedures
you have included in your UT package will use the
utPLSQL assert API to actually perform these tests.
7. The utAssert routines save the test results. The
utPLSQL assert routines will perform the specified
tests and save the results in the utPLSQL repository.
This repository is not necessarily a physical structure.
It is really just an accumulation of all of the tests for
the unit test being performed. These results will be
used later to produce a unit test report.
8. utPLSQL summarizes the test results. The
utPLSQL will summarize the results of all of the tests
and determine if the entire unit test passes or fails.
9. utPLSQL displays the results to the tester. The
result of the entire test as well as the results of each
individual test case will be reported to the tester.
How To Set Up and Start Using utPLSQL
You can use the following steps to setup and start using the
utPLSQL unit test architecture.
Step 1: Download utPLSQL
Step 2: Install utPLSQL
Step 3: Choose program to test
Step 4: Identify test cases
Step 5: Build a package for the tests
Step 6: Test your program!
STEP 1: DOWNLOAD UTPLSQL
Information about downloading utPLSQL is available at
one of the following websites:
http://oracle.oreilly.com/utplsql/
° A lot of useful information about how to use utPLSQL
° A discussion board for utPLSQL questions
http://utplsql.sourceforge.net/
° Download the utPLSQL source
° See development status, bugs, enhancements, etc.
http://utplsql.oracledeveloper.nl/
° Discussion forum for utPLSQL, documentation, links
The utPLSQL package is distributed in a zip file with full
documentation and all of the files needed to install it. You will
need to extract the files into an installation directory. The
distribution also includes documentation in HTML.
STEP 2: INSTALL UTPLSQL
Installation of utPLSQL is very simple. You will simply run
a SQL script. This SQL script will create all of the utPLSQL
objects, which include packages, tables, views, etc. It will also
set up the packages for PUBLIC access. To do this, it creates
PUBLIC synonyms, and grants access to PUBLIC. Because of
this, you really only need to install it once per database, and its
usually best to install it into its own schema. This makes it
easier to manage.
The installation documentation states that you only
need the CREATE TABLES and CREATE
PACKAGES privileges to install utPLSQL.
However, this is not quite correct (at least for
the version available when this article was
written). You will also need to grant CREATE
PUBLIC SYNONYM and EXECUTE on
SYS.DMBS_PIPE to the schema into which
utPLSQL is installed. To make this easier,
I have written a script to create a utPLSQL
owner schema with all the correct privileges.
You can get this script on my website at:
http://www.cda-llc.com/utplsql.htm.
Listing 4 is an example of installing
utPLSQL.
STEP 3: CHOOSE PROGRAM
TO TEST
When you first start using utPLSQL
you will most likely be creating unit test
packages for existing packages that have
already been developed. For your first foray
into utPLSQL you should probably select a
Listing 4. Installing utPLSQL
DECEMBER 2003 ■ 1
1
ODTUG TECHNICAL JOURNAL
fairly simple package. Starting with a simple package will let
you create a complete unit test package fairly quickly and get
you up to speed on the whole process.
If you decide to adopt this approach as a standard, you will
be creating unit test packages for all of your packages. Going
forward, you will be creating the unit test packages at the same
time as you are creating your programs.
STEP 4: IDENTIFY TEST CASES
Once you have chosen a package, you will have to
come up with the test cases that need to be tested. Usually,
the easiest way to do this is to think about what needs
to be tested and come up with a table of expected results.
When you are thinking about the test cases remember the
following conditions:
• Boundary conditions, especially parameters
• Remember how NULL values should be handled
• Remember “0” values
For example, if we were developing unit tests for the
simple PL/SQL example above (Listing 1), we might identify
the inputs and expected results shown in Table 2.
Notice that in my test cases I have included some NULLs
and 0. This set is by no means exhaustive even for this simple
function. Also, the result that you specify for a test case is not
always obvious. I had to make a decision about how NULL and
“0” values should be handled by the function. This is all part of
the design, and in fact this table becomes the truest statement
of the function design!
STEP 5: BUILD A PACKAGE FOR THE TESTS
Now we come to the main part of the
work needed to implement the unit test.
We have to build the actual PL/SQL unit
test package that we will use to test our
function. For this simple function, there
are three procedures we must include in
the UT package:
UT_SETUP — The Unit Test
setup procedure
UT_TEARDOWN —
The Unit Test
teardown procedure
UT_SALARY_MULT —
The procedure to actually
perform the unit test on
SALARY_MULT
Listing 5 shows the
specification of our unit
test package.
The package is named
“ut_EMPDEPT” because we
have put the SALARY_MULT function into a package
named EMPDEPT. In this simple case, UT_SETUP and
UT_TEARDOWN don’t do anything, so they will look
like Listing 6 in the package body.
Even in cases where they don’t do anything, they still
have to be created in the UT package so it will interface
correctly with the utPLSQL utilities.
Next, you will need to create the procedure that actually
performs the unit
test. This procedure
must follow this
naming standard:
UT_<The name
of the program
to be tested>
For example,
the unit test
procedure for this
simple function
would look like
Listing 7.
Next we have
to add the “guts” of
the procedure. You
do this by using the
utPLSQL assert
API to assert the
success or failure
of each test case.
p_input
1234
NULL
1234
NULL
0
1234
1234
p_multiplier
5
5
NULL
NULL
5
0
-10
Result
1296
NULL
1234
NULL
0
1234
1111
Table 2. Example of Expected Results
Listing 8. Specification for utAssert.eq
Continued
Listing 7. Unit Test Declaration for
ut_SALARY_MULT
Listing 6. When UT_SETUP and
UT_TEARDOWN Is Not Used
Listing 5. Specification of Unit
Test Package
ODTUG TECHNICAL JOURNAL
12 ■ DECEMBER 2003
Test Your PL/SQL Before You Write It! (Continued)
There is a whole suite of functions and procedures in the
utAssert package that you will use to do this. These routines
allow you to easily test the outcome of your results, and
report the results to utPLSQL. The results of all of the test
cases are used by utPLSQL to determine the entire unit
test outcome.
Simplest Assert: utAssert.eq
The utAssert.eq procedure is used to check for the equality
of two scalar values. It can handle many data types: dates,
strings, numbers, Boolean. If the two values passed are equal,
it records the test as successful. If the values are not equal,
then it records that the test fails. Listing 8 on page 11 is the
specification of this assert.
Where:
msg_in = A message to be displayed if the
assertion fails.
check_this_in11 = The value to be checked
against_this_in = The expected value
null_ok_in = Specifies if NULL is allowed as an
input parameter
Listing 9 is an example of using utAssert.eq for one of the
test cases listed above.
This test case is labeled “Standard Execution” and it will
see if a call to salary_mult with input parameters of 1234 and
5 will return 1296 as expected.
STEP 6: TEST YOUR PROGRAM!
Now let’s test the program with this
simple test case. To do this, we use the test
utility in the utPLSQL package, passing
it the name of the package we are testing
(“EMPDEPT” in this case). So we could run
the test using the following command:
SQL> EXECUTE utPLSQL.test(‘EMPDEPT’)
An example of running this simple
test is shown in Example 2.
The big SUCCESS tells us that the
entire unit test was successful. In the
section titled “Individual Test Case Results”
there will be a line for every test case
indicating the results of the test. In this
case, the test passed (SUCCESS), using
the utAssert.eq procedure (the “EQ”). The
label of “Standard Execution” is shown so
that if a test fails you will know which test
it is. Finally both the expected result and
the actual result are shown.
Now let’s add ALL of the tests in our
test case table. This is a matter of simply
adding additional asserts for the other test
cases. The utPLSQL package keeps track
of the overall testing status (i.e., did any
tests fail?) and reports on the results.
Listing 10 shows the unit test code for
all of the test cases in Table 2 on page 11.
Each call to an utAssert procedure
has a test description or label (i.e.,
‘p_input=NULL’ or ‘p_multiplier_pct is
negative’) and the input parameters
are specified based on the test cases we
Example 2. Successful Call Unit Test of SALARY_MULT
Listing 10. Unit Test Code for All Test Cases in Table 2
Listing 9. Example of Using utAssert.eq
DECEMBER 2003 ■ 13
ODTUG TECHNICAL JOURNAL
had identified before. The unasserted procedures will compare
the output of the calls to the program being tested against the
specified expected results.
A New utAssert Procedure: isNull
You will notice that two of the tests
did not use utAssert.eq, instead they
used utAssert.isNull. This is because,
of course, since NULL does not equal
NULL in Oracle, we have to handle
NULLs differently. The utAssert.isNull
procedure (see Listing 11) checks to see
if the specified value is null.
Where:
msg_in = Same as before,
a message to be
displayed if the
assertion fails.
check_this_in = The value to
be checked
Notice that there is no against_
this_in! This is because it is not needed
in this case, since all you are checking is if
the specified value is NULL. There is also
another related procedure called isNotNull
that performs the opposite check.
What Happens When The
Test Fails?
Now let’s run the full test
(see Example 3).
Oh no! The test failed! You can tell
this by the big FAILURE written across
your screen! But why did it fail? Looking
at the test case results we can see
that there were two specific test cases
that failed. The first failed test case
was labeled “p_multiplier_pct” and the
function returned NULL instead of
1234 as was specified. The second failure
did not even return the label because the
test case resulted in an Oracle error!
But we know that the “p_multiplier_pct=0”
test case was run immediately after
the “p_input = 0” test case, so we know
this must be the one that failed. Notice
that the last test case was not run
due to the Oracle error. This happens
when there are unhandled Oracle
exceptions. In these cases, it may take
a few iterations to get all of the tests to
even run. (This example is why I used the
weird algorithm).
To finish the development of the function, we will have to
fix these problems. The repaired function is shown in Listing
12 on page 14.
Now when the test is rerun (see Example 4), everything
is successful!
Example 4. Successful Test After Repair
Example 3. Failure of utPLSQL Test
Listing 11. Specification of the isNull Assert Routine
Continued
14 ■ DECEMBER 2003 ODTUG TECHNICAL JOURNAL
GENERATING INITIAL
TEST PACKAGES
It is a lot of work to write these UT
packages. To help with some of the routine
work involved, utPLSQL provides you
with some utilities that can generate
much of the test packages for you.
This makes it much easier to initially
setup the UT packages. These utilities
can generate skeleton UT packages
that simply consist of the package
specification and a package body with
all the UT procedures defined, but
with no unit tests in them. You would
then add the specific unit tests to
these skeleton packages. You can also
pass the generator a data set and actually
generate the code to check many or
most of your test cases if they are simple
enough. Listing 13 is an example of
using a data set to generate your
UT package.
ONE UT PACKAGE PER
APPLICATION PACKAGE
Each UT package can test as many
programs as you want. However, since
most PL/SQL programmers group
their programs into PL/SQL packages
(as they should), it is usually the best
practice to create one unit test package
per application package. This is the
way that the UT package generators
work and it is almost assumed that
this is the case in the utPLSQL code.
Here is the package spec of an example
application package (see Listing 14)
along with the package spec of its UT
package (see Listing 15).
Test Your PL/SQL Before You Write It! (Continued)
Listing 13. Using a Data Set to Generate a UT Package
Listing 12. Repaired Function
Listing14. Application Package to Test Listing 15. Associated Unit Test Package
DECEMBER 2003 ■ 15
ODTUG TECHNICAL JOURNAL
USING UT_SETUP AND
UT_TEARDOWN
We have not done much with ut_Setup
or ut_Teardown yet. That is because
our examples have been so simple that
they did not need them. If you have
more complicated test cases where you
need to set up some data or modify
package states before you can perform
the unit test, you will have to use ut_Setup
and ut_Teardown. The ut_Setup procedure
is called before any of the unit test
procedures in the UT package are
executed. It needs to set up the data,
package states, and expected result
arrays for ALL of the unit test procedures
in the package.
The ut_Teardown procedure is called
after all of the unit tests are performed.
It should clean up any data that was
used for the unit test as well as any
data that might result from the unit
test. It must also clean up any data
that is left over as a result of a unit
test Failure. For example, if the test
is supposed to delete some data, you
should add a deletion step to ut_Teardown
to clean up the data if the deletion
test fails.
The unit test package should be
completely autonomous. Ideally it should
not rely on any application data already
existing in the database. It should also
leave the database in the exact state
it was in before the tests were run.
This needs to be done so that the tests can be run
multiple times without the tester having to do any
additional work.
Listing 16 is an example of a simple use of the ut_Setup
and ut_Teardown procedures.
In this example, ut_Setup is doing two things: 1) Creating
a record in a table that is supposed to be deleted during a test,
and saving the Identifier for that record in a variable to be
used by the test case. 2) Finding a non-existent Identifier
to use for another test case. The ut_Teardown procedure is
simply removing the record that was created in ut_Setup just
in case the test fails.
Listing 17 shows an example unit test using this setup
and teardown.
The empdept.rif call in this procedure uses the variable
setup in ut_Setup to attempt an employee deletion. The
next assert call tests to see if the deletion worked. If the
test passes, then the record will be deleted and the system
state will be the same as before. If the test fails, then
ut_Teardown will cleanup the employee that was created
for this test.
More Assert Routines: utAssert.throws and
utAssert.eqQueryValue
You may have noticed that this example uses some more
utAssert routines:
utAssert.throws — This routine tests the specified
PL/SQL to see if it raises the
specified exception. In the
examples above, the expected
result is for the procedure to
raise the NO_DATA_FOUND
exception. This assert call will
fail the test if that exception is
not raised.
utAssert.eqQueryValue — This routine tests the result of a
specified query against an
expected result. In this case, the
SELECT COUNT query should
return “0” if the call to
empdept.rif succeeds.
Continued
Listing 18. Defining a Test Suite
Listing 17. Unit Test Using Work Done in ut_Setup and ut_Teardown
Listing 16. Using ut_Setup and ut_Teardown
ODTUG TECHNICAL JOURNAL
16 ■ DECEMBER 2003
Test Your PL/SQL Before You Write It! (Continued)
GROUPING TESTS INTO TEST SUITES
Each UT package is a group of related unit tests, usually
for a single application package. However, you can also group
many of these UT packages into a larger group called a test
suite. Once you do this, you can easily test the whole set of
UT packages at once. If you put all of the application packages
for your application into a test suite, you can perform a full
regression test on your application’s server side code with a
single command! Listing 18 on page 15 shows an example of
defining a test suite.
Once a test suite is defined, you can execute the entire test
suite with a single command:
SQL> exec utplsql.testsuite (‘plvision’);
Using UT Packages for Regression Testing
One big advantage of creating
formalized automatic unit test
programs is that it makes it very easy
to do a comprehensive regression
test when anything in the system
changes. For instance, you might
want to do a full regression test in the
following situations:
• Every build! — Run a full regression
test with every build to make sure that
the integration did not cause problems
with (supposedly) non-modified code.
• Oracle DB upgrade — Every
time you upgrade the Oracle DB,
there is the possibility of revealing
defects in your system. Even a minor
upgrade might “fix” a problem for
which you had coded a workaround.
If you have created these UT packages,
it is easy to ensure that the DB
upgrades did not change the behavior
of your application.
• Schema modifications — You should
run the full regression test every time
you make schema modifications. This
will ensure that your schema changes
did not cause defects in code.
• Dependent system changes —
Every time a dependent system
changes, even if your application
does not change, you can run the
regression tests to make sure your
system still works as expected.
This is especially useful if you have
integrated someone else’s PL/SQL
utilities into your system.
REGRESSION TEST EXAMPLE
Let’s detail a simple example (see
Listing 19) of how a regression test
might catch a bug due to a schema change.
Let’s say we have a routine in empdept
named get_emp_name whose purpose is
Example 6. Failure Because of Schema Change
Example 5. Successful “Get Largest Name” Result
Listing 19. Create an Employee Record
DECEMBER 2003■ 17
ODTUG TECHNICAL JOURNAL
to return the employee name given their ID. One of the tests
we put into the unit test suite was a test to ensure that the
function would retrieve the largest value possible in the table
(a boundry condition). To do this, the following code was put
into the ut_Setup routine:
This setup code simply creates an employee record with
the largest value possible in the ename column. The following
test was put into the ut_get_emp_name routine:
utAssert.eqQueryValue(‘Get Largest Name’
,’SELECT ename FROM emp WHERE empno =
‘||v_empno_to_get
,empdept.get_emp_name(v_empno_to_get));
When run before the schema change, the result is shown in
Example 5.
The value for ename that was derived by the ut_Setup
is “XXXXXXXXXX” because the ename column was a
VARCHAR2(10) column. Now let’s make a schema change:
ALTER TABLE EMP MODIFY ENAME
VARCHAR2(50);
If we run the test again (see
Example 6), our results are different!
This test now fails because the code
had a variable specification hard coded
as VARCHAR2(10), instead of using
EMPDEPT.ENAME%TYPE. This is a
fairly common defect that is introduced with such schema
changes, which is why I used it as an example.
How Can I Write the Unit Tests Before
I Write the Code?
To get the most benefit from this approach it is best to
actually write your unit tests before you write your code. This
may be a strange idea to some people who are thinking, “How
can I know what to test until I write the code?” For many this
approach will involve a big shift in the way they approach
PL/SQL development. In order to write the unit tests you will
have to think through everything your code is supposed to do
before you write even one line of code! You will have to design
your call interface, specify the parameters, and have detailed
designs before you even start. This might seem difficult to
some, but actually this “restriction” is one of the biggest
benefits of this approach. If you actually code the unit tests
first, you will be forced to think through your design, and will
invariably have a better design before you start coding. You will
also have fewer initial defects because of course you will write
the code to handle all of the unit tests you have just coded.
PROCEDURE
Here is the overall procedure you will need to follow to
write your unit tests before writing your program units:
1. Write package spec and empty program units.
First, write your package specification and empty
program units. This will give you a “compilable” shell
that will allow you to write and compile your unit test
packages. For example, the empdept.rif procedure
might look like Listing 20.
2. Use the utGen package to generate your UT
package. Now that you have your “shell” package, you
can use the utGen package in utPLSQL to generate the
structure of your UT package.
3. Identify your test cases. Next, you can identify the
test cases you want to add to the UT package.
4. Add code to test each test case. Now go ahead
and code the unit tests, ensuring that the UT
code compiles.
5. Run the UT package to ensure it works. It will fail
of course, because you have not yet written the code!
6. Now, actually write the code! Now write the code,
which should be easier because you had to think about
it while you were writing the unit tests! You should
write small pieces of functionality, and ensure each
piece passes its unit tests before continuing with other
pieces. Run the UT package frequently to ensure that
your code is written correctly.
7. When the UT package returns “SUCCESS”, you’re
done! When you see the big SUCCESS, you know you
have finished your program AND that you have
written high quality code!
IS THIS ALWAYS POSSIBLE?
Is it actually possible to always write the unit tests first?
Well, to be honest, it is not always possible to do this. There are
certain situations where your application architecture or other
constraints may prevent you from always approaching it this
way. But if you start with this as your goal, you will be much
better off than if you don’t even try.
Continued
Listing 20. Compilable Shell Before Tests Are Added
Figure 2. Ounit Sample Screen
ODTUG TECHNICAL JOURNAL
18 ■ DECEMBER 2003
Hurdles to Overcome
Of course nothing is ever as easy as it seems at first (if this
even seems easy for you). If you really want to do this there are
some challenges you will have to overcome:
• Writing the UT packages can take as long
(or longer) as writing the code. But as I said before,
I think it’s really worth it in the long run. This is just
something that you will have to get used to.
• Your testing process will have to change! For
many organizations change can be difficult. Especially
if you really want to do this but are not in the position
to mandate it.
• Developers may resist the change. Many developers
may think that this sort of testing is overkill, and may
fail to see the value in it. If possible, try to convince your
whole team that this is the right approach. It is much
easier to affect change if everyone agrees that this is the
way to go.
• There is no nice UI. Currently
there is no user friendly UI for
utPLSQL. This may change in the
future; I know that Quest software
had considered adding a front end
to utPLSQL to one of their packages,
though I don’t know the status of
that at this time. Also, Michael O’Neill
has developed a Web PL/SQL UI
for utPLSQL, but I have not looked at
it yet. It’s available at: http://
sourceforge.net/projects/plcodebrew
Ounit — A GUI Front End
to utPLSQL
If you are wondering if there are some
nicer GUI tools that would support this
unit testing approach, you are not alone.
In fact, Steven Feuerstein and Patrick
Barel have teamed up to develop a nice
GUI front end. Figure 2 on page 17 is an
example screenshot.
This program is called Ounit, and
version 1.0 is currently available for
download at http://www.ounit.com
This program is currently free.
Measuring Unit Test Code
Coverage with
DBMS_PROFILER
When you have written your unit
tests, you may wonder if you have actually
written good unit tests! How can you
know this? Well, mostly you will know
based on your experience. However,
one unit test quality metric you can
actually calculate is how much of your
code is actually tested by your suite
of unit tests. This can be called a “Code
Coverage” metric for your unit tests.
To do this, you would use the utilities in
Test Your PL/SQL Before You Write It! (Continued)
Listing 23. SQL Script to Report Results
Listing 22. Saving Statistics in plsql_profiler Tables
Listing 21. Script to Accumulate PL/SQL Statistics
Listing 24. Code Coverage Report
ODTUG TECHNICAL JOURNAL DECEMBER 2003 ■ 19
the DBMS_PROFILER package to accumulate statistics
about your executed PL/SQL code while you are running your
unit tests. You can then use these statistics to run a report
that shows you how much of your PL/SQL code was actually
executed by your tests. If you don’t have 100 percent of your
code executed, then either you are missing some test cases
you should have, or you have orphaned code.
Here is an example of using DBMS_PROFILER to perform
a code coverage test:
1) First, accumulate the PL/SQL statistics using a script
like that shown in Listing 21.
2) The statistics from your test run will now be saved in
the plsql_profiler tables (see Listing 22).
3) Listing 23 shows a SQL script that reports the results.
4) Listing 24 shows an example of running this report for
the example package used in this article.
This report tells me that my test cases only actually
executed around 30 percent of the code in my package! I guess I
have a few more test cases to write.
To find out more about DBMS_PROFILER, including how
to install it in your environment, look in the Oracle Supplied
PL/SQL Packages Reference in the Oracle Documentation.
Conclusion
It is my opinion that the utPLSQL approach is well worth
the effort and will lead to much better quality PL/SQL code. It
will encourage better code design, increased modularity, and a
more repeatable testing process. In the long run it will lead to
lower development costs because of the reduced number of
defects, which are expensive. And you even get to say you used
an XT practice! It is my intention to encourage the use of this
approach for ANY new PL/SQL project that I am involved with.
Happy Testing!
About the Author
Ken Atkins is a cofounder of Creative Design Associates
(www.cda-llc.com), a consultancy that focuses on Oracle
Designer, SCM, Project Management, and Oracle Development
Tools. He has more than 12 years of experience developing
applications with the Oracle Database and tools. Ken is a
popular presenter at national Oracle conferences, and has been
active in ODTUG for over seven years, including a term on
the ODTUG Board of Directors. He is also a coauthor of Oracle
Designer System Generation (Oracle Press). Ken maintains
an Oracle tip site at: http://www.arrowsent.com/oratip.
If you have any questions or comments about this article, you
can e-mail Ken at katkins@cda-llc.com. You can download this
paper as well as other papers at www.cda-llc.com.
Let Us Show You How!
JUNE 20-24, 2004
THE WESTIN KIERLAND RESORT & SPA
SCOTTSDALE, ARIZONA
910.452.7444
www.odtug.com
Ad

More Related Content

Similar to utplsql.pdf (20)

Testing In Software Engineering
Testing In Software EngineeringTesting In Software Engineering
Testing In Software Engineering
kiansahafi
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
Sergey Aganezov
 
Software presentation
Software presentationSoftware presentation
Software presentation
JennaPrengle
 
Test driven development and unit testing with examples in C++
Test driven development and unit testing with examples in C++Test driven development and unit testing with examples in C++
Test driven development and unit testing with examples in C++
Hong Le Van
 
Fundamentals of testing
Fundamentals of testingFundamentals of testing
Fundamentals of testing
ANDRI HAIRIYADI, S.Kom.
 
TDD Workshop UTN 2012
TDD Workshop UTN 2012TDD Workshop UTN 2012
TDD Workshop UTN 2012
Facundo Farias
 
Unit testing (Exploring the other side as a tester)
Unit testing (Exploring the other side as a tester)Unit testing (Exploring the other side as a tester)
Unit testing (Exploring the other side as a tester)
Abhijeet Vaikar
 
assertYourself - Breaking the Theories and Assumptions of Unit Testing in Flex
assertYourself - Breaking the Theories and Assumptions of Unit Testing in FlexassertYourself - Breaking the Theories and Assumptions of Unit Testing in Flex
assertYourself - Breaking the Theories and Assumptions of Unit Testing in Flex
michael.labriola
 
Testing Hourglass at Jira Frontend - by Alexey Shpakov, Sr. Developer @ Atlas...
Testing Hourglass at Jira Frontend - by Alexey Shpakov, Sr. Developer @ Atlas...Testing Hourglass at Jira Frontend - by Alexey Shpakov, Sr. Developer @ Atlas...
Testing Hourglass at Jira Frontend - by Alexey Shpakov, Sr. Developer @ Atlas...
Applitools
 
Unit & integration testing
Unit & integration testingUnit & integration testing
Unit & integration testing
Pavlo Hodysh
 
Growing Object Oriented Software
Growing Object Oriented SoftwareGrowing Object Oriented Software
Growing Object Oriented Software
Annmarie Lanesey
 
Learn sqa from expert class 2reviewed
Learn sqa from expert class 2reviewedLearn sqa from expert class 2reviewed
Learn sqa from expert class 2reviewed
Sharmin Khan Urmi
 
Software testing
Software testingSoftware testing
Software testing
Ashu Bansal
 
Unit testing, principles
Unit testing, principlesUnit testing, principles
Unit testing, principles
Renato Primavera
 
5-Ways-to-Revolutionize-Your-Software-Testing
5-Ways-to-Revolutionize-Your-Software-Testing5-Ways-to-Revolutionize-Your-Software-Testing
5-Ways-to-Revolutionize-Your-Software-Testing
Mary Clemons
 
Software unit4
Software unit4Software unit4
Software unit4
Himanshu Awasthi
 
SOFTWARE TESTING UNIT-4
SOFTWARE TESTING UNIT-4  SOFTWARE TESTING UNIT-4
SOFTWARE TESTING UNIT-4
Mohammad Faizan
 
TDD Best Practices
TDD Best PracticesTDD Best Practices
TDD Best Practices
Attila Bertók
 
Software testing
Software testingSoftware testing
Software testing
Abhishek Gautam
 
Jason Olson - Test What You've Built
Jason Olson - Test What You've BuiltJason Olson - Test What You've Built
Jason Olson - Test What You've Built
John Zozzaro
 
Testing In Software Engineering
Testing In Software EngineeringTesting In Software Engineering
Testing In Software Engineering
kiansahafi
 
Software presentation
Software presentationSoftware presentation
Software presentation
JennaPrengle
 
Test driven development and unit testing with examples in C++
Test driven development and unit testing with examples in C++Test driven development and unit testing with examples in C++
Test driven development and unit testing with examples in C++
Hong Le Van
 
Unit testing (Exploring the other side as a tester)
Unit testing (Exploring the other side as a tester)Unit testing (Exploring the other side as a tester)
Unit testing (Exploring the other side as a tester)
Abhijeet Vaikar
 
assertYourself - Breaking the Theories and Assumptions of Unit Testing in Flex
assertYourself - Breaking the Theories and Assumptions of Unit Testing in FlexassertYourself - Breaking the Theories and Assumptions of Unit Testing in Flex
assertYourself - Breaking the Theories and Assumptions of Unit Testing in Flex
michael.labriola
 
Testing Hourglass at Jira Frontend - by Alexey Shpakov, Sr. Developer @ Atlas...
Testing Hourglass at Jira Frontend - by Alexey Shpakov, Sr. Developer @ Atlas...Testing Hourglass at Jira Frontend - by Alexey Shpakov, Sr. Developer @ Atlas...
Testing Hourglass at Jira Frontend - by Alexey Shpakov, Sr. Developer @ Atlas...
Applitools
 
Unit & integration testing
Unit & integration testingUnit & integration testing
Unit & integration testing
Pavlo Hodysh
 
Growing Object Oriented Software
Growing Object Oriented SoftwareGrowing Object Oriented Software
Growing Object Oriented Software
Annmarie Lanesey
 
Learn sqa from expert class 2reviewed
Learn sqa from expert class 2reviewedLearn sqa from expert class 2reviewed
Learn sqa from expert class 2reviewed
Sharmin Khan Urmi
 
Software testing
Software testingSoftware testing
Software testing
Ashu Bansal
 
5-Ways-to-Revolutionize-Your-Software-Testing
5-Ways-to-Revolutionize-Your-Software-Testing5-Ways-to-Revolutionize-Your-Software-Testing
5-Ways-to-Revolutionize-Your-Software-Testing
Mary Clemons
 
SOFTWARE TESTING UNIT-4
SOFTWARE TESTING UNIT-4  SOFTWARE TESTING UNIT-4
SOFTWARE TESTING UNIT-4
Mohammad Faizan
 
Jason Olson - Test What You've Built
Jason Olson - Test What You've BuiltJason Olson - Test What You've Built
Jason Olson - Test What You've Built
John Zozzaro
 

Recently uploaded (20)

Reagent dosing (Bredel) presentation.pptx
Reagent dosing (Bredel) presentation.pptxReagent dosing (Bredel) presentation.pptx
Reagent dosing (Bredel) presentation.pptx
AlejandroOdio
 
Data Structures_Searching and Sorting.pptx
Data Structures_Searching and Sorting.pptxData Structures_Searching and Sorting.pptx
Data Structures_Searching and Sorting.pptx
RushaliDeshmukh2
 
Smart_Storage_Systems_Production_Engineering.pptx
Smart_Storage_Systems_Production_Engineering.pptxSmart_Storage_Systems_Production_Engineering.pptx
Smart_Storage_Systems_Production_Engineering.pptx
rushikeshnavghare94
 
ADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITY
ADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITYADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITY
ADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITY
ijscai
 
QA/QC Manager (Quality management Expert)
QA/QC Manager (Quality management Expert)QA/QC Manager (Quality management Expert)
QA/QC Manager (Quality management Expert)
rccbatchplant
 
RICS Membership-(The Royal Institution of Chartered Surveyors).pdf
RICS Membership-(The Royal Institution of Chartered Surveyors).pdfRICS Membership-(The Royal Institution of Chartered Surveyors).pdf
RICS Membership-(The Royal Institution of Chartered Surveyors).pdf
MohamedAbdelkader115
 
Fort night presentation new0903 pdf.pdf.
Fort night presentation new0903 pdf.pdf.Fort night presentation new0903 pdf.pdf.
Fort night presentation new0903 pdf.pdf.
anuragmk56
 
Compiler Design Unit1 PPT Phases of Compiler.pptx
Compiler Design Unit1 PPT Phases of Compiler.pptxCompiler Design Unit1 PPT Phases of Compiler.pptx
Compiler Design Unit1 PPT Phases of Compiler.pptx
RushaliDeshmukh2
 
"Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E...
"Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E..."Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E...
"Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E...
Infopitaara
 
Lidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptx
Lidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptxLidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptx
Lidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptx
RishavKumar530754
 
"Feed Water Heaters in Thermal Power Plants: Types, Working, and Efficiency G...
"Feed Water Heaters in Thermal Power Plants: Types, Working, and Efficiency G..."Feed Water Heaters in Thermal Power Plants: Types, Working, and Efficiency G...
"Feed Water Heaters in Thermal Power Plants: Types, Working, and Efficiency G...
Infopitaara
 
ELectronics Boards & Product Testing_Shiju.pdf
ELectronics Boards & Product Testing_Shiju.pdfELectronics Boards & Product Testing_Shiju.pdf
ELectronics Boards & Product Testing_Shiju.pdf
Shiju Jacob
 
Process Parameter Optimization for Minimizing Springback in Cold Drawing Proc...
Process Parameter Optimization for Minimizing Springback in Cold Drawing Proc...Process Parameter Optimization for Minimizing Springback in Cold Drawing Proc...
Process Parameter Optimization for Minimizing Springback in Cold Drawing Proc...
Journal of Soft Computing in Civil Engineering
 
Smart Storage Solutions.pptx for production engineering
Smart Storage Solutions.pptx for production engineeringSmart Storage Solutions.pptx for production engineering
Smart Storage Solutions.pptx for production engineering
rushikeshnavghare94
 
DSP and MV the Color image processing.ppt
DSP and MV the  Color image processing.pptDSP and MV the  Color image processing.ppt
DSP and MV the Color image processing.ppt
HafizAhamed8
 
Explainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptx
Explainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptxExplainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptx
Explainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptx
MahaveerVPandit
 
Level 1-Safety.pptx Presentation of Electrical Safety
Level 1-Safety.pptx Presentation of Electrical SafetyLevel 1-Safety.pptx Presentation of Electrical Safety
Level 1-Safety.pptx Presentation of Electrical Safety
JoseAlbertoCariasDel
 
MAQUINARIA MINAS CEMA 6th Edition (1).pdf
MAQUINARIA MINAS CEMA 6th Edition (1).pdfMAQUINARIA MINAS CEMA 6th Edition (1).pdf
MAQUINARIA MINAS CEMA 6th Edition (1).pdf
ssuser562df4
 
introduction to machine learining for beginers
introduction to machine learining for beginersintroduction to machine learining for beginers
introduction to machine learining for beginers
JoydebSheet
 
railway wheels, descaling after reheating and before forging
railway wheels, descaling after reheating and before forgingrailway wheels, descaling after reheating and before forging
railway wheels, descaling after reheating and before forging
Javad Kadkhodapour
 
Reagent dosing (Bredel) presentation.pptx
Reagent dosing (Bredel) presentation.pptxReagent dosing (Bredel) presentation.pptx
Reagent dosing (Bredel) presentation.pptx
AlejandroOdio
 
Data Structures_Searching and Sorting.pptx
Data Structures_Searching and Sorting.pptxData Structures_Searching and Sorting.pptx
Data Structures_Searching and Sorting.pptx
RushaliDeshmukh2
 
Smart_Storage_Systems_Production_Engineering.pptx
Smart_Storage_Systems_Production_Engineering.pptxSmart_Storage_Systems_Production_Engineering.pptx
Smart_Storage_Systems_Production_Engineering.pptx
rushikeshnavghare94
 
ADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITY
ADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITYADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITY
ADVXAI IN MALWARE ANALYSIS FRAMEWORK: BALANCING EXPLAINABILITY WITH SECURITY
ijscai
 
QA/QC Manager (Quality management Expert)
QA/QC Manager (Quality management Expert)QA/QC Manager (Quality management Expert)
QA/QC Manager (Quality management Expert)
rccbatchplant
 
RICS Membership-(The Royal Institution of Chartered Surveyors).pdf
RICS Membership-(The Royal Institution of Chartered Surveyors).pdfRICS Membership-(The Royal Institution of Chartered Surveyors).pdf
RICS Membership-(The Royal Institution of Chartered Surveyors).pdf
MohamedAbdelkader115
 
Fort night presentation new0903 pdf.pdf.
Fort night presentation new0903 pdf.pdf.Fort night presentation new0903 pdf.pdf.
Fort night presentation new0903 pdf.pdf.
anuragmk56
 
Compiler Design Unit1 PPT Phases of Compiler.pptx
Compiler Design Unit1 PPT Phases of Compiler.pptxCompiler Design Unit1 PPT Phases of Compiler.pptx
Compiler Design Unit1 PPT Phases of Compiler.pptx
RushaliDeshmukh2
 
"Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E...
"Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E..."Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E...
"Boiler Feed Pump (BFP): Working, Applications, Advantages, and Limitations E...
Infopitaara
 
Lidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptx
Lidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptxLidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptx
Lidar for Autonomous Driving, LiDAR Mapping for Driverless Cars.pptx
RishavKumar530754
 
"Feed Water Heaters in Thermal Power Plants: Types, Working, and Efficiency G...
"Feed Water Heaters in Thermal Power Plants: Types, Working, and Efficiency G..."Feed Water Heaters in Thermal Power Plants: Types, Working, and Efficiency G...
"Feed Water Heaters in Thermal Power Plants: Types, Working, and Efficiency G...
Infopitaara
 
ELectronics Boards & Product Testing_Shiju.pdf
ELectronics Boards & Product Testing_Shiju.pdfELectronics Boards & Product Testing_Shiju.pdf
ELectronics Boards & Product Testing_Shiju.pdf
Shiju Jacob
 
Smart Storage Solutions.pptx for production engineering
Smart Storage Solutions.pptx for production engineeringSmart Storage Solutions.pptx for production engineering
Smart Storage Solutions.pptx for production engineering
rushikeshnavghare94
 
DSP and MV the Color image processing.ppt
DSP and MV the  Color image processing.pptDSP and MV the  Color image processing.ppt
DSP and MV the Color image processing.ppt
HafizAhamed8
 
Explainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptx
Explainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptxExplainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptx
Explainable-Artificial-Intelligence-XAI-A-Deep-Dive (1).pptx
MahaveerVPandit
 
Level 1-Safety.pptx Presentation of Electrical Safety
Level 1-Safety.pptx Presentation of Electrical SafetyLevel 1-Safety.pptx Presentation of Electrical Safety
Level 1-Safety.pptx Presentation of Electrical Safety
JoseAlbertoCariasDel
 
MAQUINARIA MINAS CEMA 6th Edition (1).pdf
MAQUINARIA MINAS CEMA 6th Edition (1).pdfMAQUINARIA MINAS CEMA 6th Edition (1).pdf
MAQUINARIA MINAS CEMA 6th Edition (1).pdf
ssuser562df4
 
introduction to machine learining for beginers
introduction to machine learining for beginersintroduction to machine learining for beginers
introduction to machine learining for beginers
JoydebSheet
 
railway wheels, descaling after reheating and before forging
railway wheels, descaling after reheating and before forgingrailway wheels, descaling after reheating and before forging
railway wheels, descaling after reheating and before forging
Javad Kadkhodapour
 
Ad

utplsql.pdf

  • 1. DECEMBER 2003 ■ 5 ODTUG TECHNICAL JOURNAL Do You Test Your PL/SQL? Everyone thinks they test their code, but how robust is your PL/SQL testing? Does the following dialog sound at all familiar? If I ask: “Do You Test Your PL/SQL?” what is your answer? “Of course we do! Everybody tests their code don’t they? Since it works, it must have been tested.” Then you have documented test plans? “Well....” And you have plans for all testing types: unit test, stress testing, system tests, regression tests... “Uh....” And of course your testing is automated and repeatable. “Well, what I mean is that we unit test our PL/SQL.” So your unit tests are repeatable, and can be run by any developer. “We have the programmer unit test his own code, it’s easier...” And the testing is automated of course. “Well, I think they use SQL scripts...” Of course, how to use the scripts and the purpose of each test case is documented. “OK, OK, I see your point. But the code works, since it passed the system test!” OK, so let’s be honest, what testing do you really do? “Well, the programmer tests it a bit, and when he is happy we integrate it. If it does not crash the system and seems to do what it is supposed to do we’re happy. Oh, and we do have the team lead review the code...” Of course, you probably have better testing practices than this scenario, but everyone can probably enhance their testing! What is Unit Testing? Unit testing is only one of the types of testing that a system will undergo during the system develop- ment process, but it is an important one! TYPES OF TESTING Table 1 is a list of some of the standard testing that might be done during system development. You may not quite agree with these definitions, or you may give these test slightly different names. However, most systems undergo various levels of tests that should fit within this spectrum. This article is going to focus on unit testing. UNIT TESTING Here is a list of some of the features of unit testing: • Testing of individual program units • Usually done by the person who programs the code • However, can be done by someone else on the development team • Does NOT test the program unit in the context of the entire system • In PL/SQL, this usually will be done for procedures and functions Basically, unit testing is the testing that a programmer does on a specific program unit they have written. It’s often considered to be simply part of the development effort. TestYour PL/SQL BeforeYou Write It! — Ken Atkins Creative Design Associates ODTUG MEMBER Award Winner ODTUG 2003 EDITOR’S CHOICE Continued Acceptance Test System Test Integration Test Stress Test Regression Test Unit Test Overall system testing that is done to prove that the system meets the requirements. Does not necessarily test every bit of functionality, but will test overall system functionality. Test the entire system to ensure that every component works correctly as it is built. The test is performed on the entire configuration/build that will be delivered. The system test is usually a complete test that will test every component. Performed on a specific program unit or subsystem to ensure that it integrates with other components of the system. Test of certain program units or subsystems for multiple users or processes to ensure that the system performs efficiently under high transaction volume. Overall system testing that is done to prove that the system still works correctly after changes. Usually done during system patches or upgrades, database upgrades, or dependent system upgrades, even if the system being tested does not change. Testing of specific program unit to ensure that it works as specified. The unit test is done as a standalone test of the program unit without any dependency or interaction with other program units. Test Type Description Table 1. Standard Test Descriptions
  • 2. ODTUG TECHNICAL JOURNAL 6 ■ DECEMBER 2003 Test Your PL/SQL Before You Write It! (Continued) Why Perform “Formal” Unit Testing? There are many reasons why you should consider performing “formal” unit testing: • To develop code that actually works! If you don’t actually think about and plan your testing, there will be no guarantee that the code will work correctly. • To ensure code works any way it is used. If you use good design practices and build your code in a very modular fashion, you will often end up with generic modular programs that can be used in many ways throughout your application. When you first build and integrate these modules, you will make sure they work correctly the way they are initially used. However, unless you plan specific unit tests you may not make sure that they work correctly when used in other ways. These same program units may be used later in the development process in a fashion that was not fully tested during the initial development. This leaves your system open for defects to be easily introduced later. • To ensure that code meets design requirements. A good unit test will prove that a program meets its design requirements. It can also codify and clarify those requirements so that there is less confusion and error in the design implementation. Often during the development of the unit tests, the developer will find out that they misunderstood the requirements or they will find errors in the design. • To deliver applications on time! This might sound counter-intuitive since a robust implementation of formal unit tests such as I am proposing will seem to add to the program unit development time. I often hear people say that they don’t have time to do this sort of unit testing. In my opinion, this perception is incorrect. All of the work you need to do to implement good unit tests has to be done anyway. The developer still has to spend time understanding the program’s requirements. He still has to perform some sort of testing. And if he produces poorly tested code, he will have to spend a lot of time debugging problems uncovered during system testing or integration. • To develop code that can be shared. If a program unit is robust and thoroughly tested, it is much more likely that someone else on the development team will be able to use it instead of redeveloping the same functionality. Also, producing the unit test makes the developer think through the call interface, and the developer will invariably come up with a better call interface with more parameters if they think through the unit testing needed. I have also found that if code functions poorly, or is not designed correctly, it will not be used by other developers even when it should. The other developers will simply write their own code instead of using someone else’s poorly implemented code. Why Automate Unit Tests? There are many reasons why unit tests should be automated. (Obviously, they can’t be 100 percent automated, someone has to at least push the button!) Here are some of the reasons: • To ensure that unit tests are 100 percent repeatable. If your unit tests are automated, you will always know that the program unit is tested the same way, and with the same parameters. If these tests are not automated, then the quality of the testing is left to the whim of the person doing the testing. • Automation makes it easy to repeat tests when conditions change. If the testing is automated, then you can easily repeat the tests whenever something changes that might affect your system. Some examples of the changes where your system might benefit from a repeat of the unit tests are: ° Upgrade in database version ° Changes to your data model ° New versions of utilities or dependent systems • Automation allows any team member to perform tests. If the unit tests are ad-hoc, only the program unit developer will be able to easily and thoroughly test the program. If the unit tests are automated, you can easily have any member of your team perform the test and get thorough testing. If someone has to make a change to the code, they will only need to learn enough of the code to make the specified change. The automated unit test should ensure that the rest of the code continues to function as designed. • To save time (in the long run!). Initially, there is a lot of effort involved in automating the unit tests. The first time you perform your unit tests it will take much longer to automate them than to simply perform ad-hoc tests. However, when you rerun the tests later during your system development process you will benefit from the initial work. Why Don’t People Automate Unit Tests? There are many reasons that automated unit testing is not more common in PL/SQL development projects. The most common reason is probably: “We don’t have time!” Many times the project timeline is too tight to easily allow for very robust automated unit tests. Other people think that it is just too much work for not enough benefit (I hope to convince you otherwise!). Sometimes I think that the real reason is that writing the unit tests is just too boring! You may think I am being facetious about this, but I’m not. All too often the real reason that decisions are made have more to do with the preferences of the development team than any real business justification. There are always enough excuses given for why our practices do not produce the best results. What we should be looking for are reasons to implement practices that improve our code in a consistent fashion. I hope this article may help convince you that it is beneficial to write automated unit test scripts to test your PL/SQL.
  • 3. ODTUG TECHNICAL JOURNAL Typical Unit Testing Scenario Let’s compare this “nirvana” to a “typical” unit testing scenario, and see how close it is to the goals above. We will start with a very simple example: A function to multiply a number by a percentage. Listing 1 is the example code. This example is kept simple on purpose so that we can focus on the unit testing technique, not on the example. Also, don’t say anything about the weird algorithm; it is used on purpose (you’ll see why later). You might use this function like this: v_RetValue := salary_mult(v_InValue, 10); Ad-Hoc testing OK, now let’s test it. What should I test for? How about this: SQL> EXEC DBMS_OUTPUT.PUT_LINE (salary_mult(1234, 10) ); 1357 Let’s try another test: SQL> EXEC DBMS_OUTPUT.PUT_LINE (salary_mult(0, 10) ); 0 Or one more: SQL> EXEC DBMS_OUTPUT.PUT_LINE (salary_mult(1234, -10) ); 1111 OK, that’s all I can think of.... I guess it works. PUTTING IT INTO A SCRIPT A better approach might be to put the tests into a SQL script (see Listing 2). Now you can run all of the tests with one command, shown in Listing 3. But what do these results mean? Did the test pass or fail? You can’t easily tell from the results. WHAT IS WRONG WITH THE AD-HOC APPROACH? There are many problems with this “ad-hoc” approach to unit testing: • The testing is not very thorough • There is no standardization of the unit tests • No easy way to record results • Interpretation of test results relies on knowledge of tester • More work for maintenance programmers since they have to learn how to test the code • You are actually letting your users test the code! How can we do better? Write Automated Formal Unit Tests Before Writing the Code! One way to do a much better job in this area is to write your unit tests before you actually write the code! This approach has a lot of advantages, as you will see. This idea is one of the practices associated with Extreme Programming (XP). ABOUT XP (EXTREME PROGRAMMING) Extreme Programming (or XP) takes standard, common sense, well-accepted programming practices and... takes them to the extreme! For example, in Extreme Programming: • Peer review of your code (a standard practice) — becomes Pair Programming • Seeking customer input for requirements—becomes Customer expert on development team • Everyone’s code should work together —becomes Integrate often (i.e., daily) • And your code should be tested—becomes Write unit tests BEFORE writing the code! WHY WRITE UNIT TESTS BEFORE THE CODE? Why would you want to write the unit tests before writing the code? After all, you don’t even have anything to test yet! There are many reasons this approach will lead to better, more supportable code with less defects. • Leads to better design of program unit. Writing the unit test before writing the code leads to better design of the program unit. The programmer will have to really think through the call interface in order to write the unit tests, and this will often uncover problems with the initial design that can be remedied before the code is actually written. Listing 2. Testing with an SQL Script Listing 3. Executing the SQL Test Script Listing 1. Simple PL/SQL Program to Be Tested DECEMBER 2003 ■ 7 Continued
  • 4. 8 ■ DECEMBER 2003 ODTUG TECHNICAL JOURNAL Test Your PL/SQL Before You Write It! (Continued) • Forces developer to think about the interface before the algorithm. This will lead to code that is more easily reused by other team members. For example, you might uncover the need for additional parameters. This approach also leads to the parameters being defined in a way that is easy to understand and use. • Encourages developers to think modularly. Creating unit tests for large monolithic programs can be very difficult! It is much easier to create the unit tests for small program units that do only one thing. Therefore, this unit test approach often leads to the developers creating more modular code. More modular code can help increase code reusability. • You can tell when a program is done! How do you know when you are finished writing a program? You could say that when you feel you have met all of the requirements, then the program is done. But how do you prove you have met all of the requirements? Maybe when the code is system-tested? Otherwise it’s just the developer’s opinion. Also, how can you measure partial completion? How often does code get stuck in the permanent 90 percent done status? Using the unit test first approach, you know when the code is done....it is done when it passes the unit tests! If you set up the right environment, you can use this fact to get a complete and accurate picture of how close to completion a system is (at least after the unit tests have been written!). WHEN SHOULD YOU WRITE UNIT TESTS? There are a few different times in the program unit’s life cycle where you would want to write or add to its unit tests. Here are some of them: • Write unit tests before you write any code. To take advantage of this approach, you should write the unit tests before you actually write the code. Ideally, you should write ALL of the unit test programs before writing any code. However, for complicated systems this might not be possible. Often you will have to write some of the code before you can even write unit tests for other parts of the code. Also, you may not be able to even design parts of the system until you have written other parts of the system. However, you should get as close as possible. • Write another unit test before you fix each bug. You should also write another unit test case before you fix each bug. This test case will be used to prove you have actually fixed the bug, and to ensure that the bug remains fixed. How many times have you fixed a bug only to have it crop up again for some reason? Adding a test case for each bug ensures that the bug remains fixed even when other aspects of the system change. • Write unit tests before making any enhancements. Each enhancement will also start with a new unit test or additional unit test cases. These will be used to ensure that the enhancement was done correctly. Writing the unit tests first will also ensure that the programmer really understands the enhancement before he starts to code it. How often have you coded an enhancement only to find that what you coded was not what they wanted? Another advantage of writing the unit tests is that they become de facto documentation for the functionality requested in the enhancement. But That’s A Lot of Work! You bet it is! Developing high quality systems is not easy. In this approach, you code a little and test a lot. In fact, coding the unit test will often take more time than actually coding the program unit. This is especially true for smaller utility programs. Of course you get the most benefit from these types of programs because many other programs often use them and you want them to be bulletproof. ACTUALLY, IT WILL SAVE WORK IN THE LONG RUN In my opinion, this approach will actually save work in the long run. This is because the fewer bugs you have to fix, and the earlier you catch them in the process, the cheaper they are to fix. Detecting and fixing a bug during the build phase is orders of magnitude cheaper than discovering a bug in your production system. If used consistently and correctly this approach can lead to systems where the only bugs are due to design or analysis errors, not programming bugs. Your code will work right the first time! AUTOMATE AND STANDARDIZE AS MUCH AS POSSIBLE One way to reduce the amount of work this approach takes is to automate the process as much as possible. Automation will save your developers time in the development and execution of the unit tests. It will also ensure that all of your developers will be using the same unit test approach. Good unit test automation will also make it easy to perform the tests and see the results. Wouldn’t it Be Great If... OK, so far I have been making a case for creating format automated unit tests for your PL/SQL code. But how do you go about doing this? Wouldn’t it be great if: • Everyone on the project used the same unit test approach
  • 5. ODTUG TECHNICAL JOURNAL • It was fairly easy to construct unit tests in a consistent fashion • It was easy to run the unit tests and see the results • All of the unit tests could be grouped together into a unit test suite • Automated unit testing was simply a part of your development cycle • No program goes to QA without passing a formal unit test utPLSQL to the Rescue! Fortunately, there is a way to easily achieve many of the benefits I have been extolling! The utPLSQL package is an open source unit testing framework that is available for use with PL/SQL unit testing. It was originally developed and championed by Steven Feuerstein, the PL/SQL guru (author of many great books about PL/SQL). The framework is based on a standard Extreme Programming (XP) idea. It is modeled after some other XP unit testing frameworks, specifically Junit and Xunit. Now that I’ve convinced you of the value of this approach (I hope), the rest of this discussion will focus on a specific example of using utPLSQL to write and execute unit tests. EXAMPLE OF UTPLSQL RESULT Let’s start with an example of using utPLSQL. Example 1 shows a successful test. This example shows that the EMPDEPT package successfully passed the unit tests. The details of each test are shown (most of the test cases were removed from the output for this example). The utPLSQL Architecture Here is an overview of the utPLSQL architecture. It may seem rather complicated, but when you start using it you will see that it’s really not too bad. I will summarize the unit test development process using utPLSQL. Refer to Figure 1 for a diagram of the following steps. 1. Programmer writes UT package. In order to automate the unit tests, you will have to write them in PL/SQL. Usually you will create one unit test package for each PL/SQL package. This unit test package will have to conform to the standards dictated by the utPLSQL architecture. For example there has to be a setup and a teardown procedure in the package. 2. Programmer executes utPLSQL.test. When the unit test package is finished, the programmer (or other tester) will call the test procedure in the utPLSQL package to actually perform the tests. The name of the package to be tested is passed as a parameter. 3. utPLSQL.test calls code in UT package. The unit test package for the specified package will be called by utPLSQL. The unit test package is always named the same as the package it tests with a “UT_” prefix. 4. Setup (and later teardown) data for test. The UT_Setup procedure in your UT package is called first by utPLSQL. This procedure performs any setup tasks needed to perform all of the unit tests in the package. This includes creating test data, storing expected results in PL/SQL tables, setting up package states, anything you need to do to perform the tests. 5. The UT package calls your actual code. Next, utPLSQL will call your actual code. Each procedure or function in your package for which you want to perform unit tests will have a procedure in this package. Then utPLSQL reads the UT package spec and automatically calls all of the unit test procedures you have defined. Continued Example 1. Successful Test Using utPLSQL DECEMBER 2003 ■ 9 Figure 1. The utPLSQL Architecture
  • 6. ODTUG TECHNICAL JOURNAL 10 ■ DECEMBER 2003 Test Your PL/SQL Before You Write It! (Continued) 6. The UT package Asserts the tests using the utPLSQL assert API. Each of the unit test procedures you have included in your UT package will use the utPLSQL assert API to actually perform these tests. 7. The utAssert routines save the test results. The utPLSQL assert routines will perform the specified tests and save the results in the utPLSQL repository. This repository is not necessarily a physical structure. It is really just an accumulation of all of the tests for the unit test being performed. These results will be used later to produce a unit test report. 8. utPLSQL summarizes the test results. The utPLSQL will summarize the results of all of the tests and determine if the entire unit test passes or fails. 9. utPLSQL displays the results to the tester. The result of the entire test as well as the results of each individual test case will be reported to the tester. How To Set Up and Start Using utPLSQL You can use the following steps to setup and start using the utPLSQL unit test architecture. Step 1: Download utPLSQL Step 2: Install utPLSQL Step 3: Choose program to test Step 4: Identify test cases Step 5: Build a package for the tests Step 6: Test your program! STEP 1: DOWNLOAD UTPLSQL Information about downloading utPLSQL is available at one of the following websites: http://oracle.oreilly.com/utplsql/ ° A lot of useful information about how to use utPLSQL ° A discussion board for utPLSQL questions http://utplsql.sourceforge.net/ ° Download the utPLSQL source ° See development status, bugs, enhancements, etc. http://utplsql.oracledeveloper.nl/ ° Discussion forum for utPLSQL, documentation, links The utPLSQL package is distributed in a zip file with full documentation and all of the files needed to install it. You will need to extract the files into an installation directory. The distribution also includes documentation in HTML. STEP 2: INSTALL UTPLSQL Installation of utPLSQL is very simple. You will simply run a SQL script. This SQL script will create all of the utPLSQL objects, which include packages, tables, views, etc. It will also set up the packages for PUBLIC access. To do this, it creates PUBLIC synonyms, and grants access to PUBLIC. Because of this, you really only need to install it once per database, and its usually best to install it into its own schema. This makes it easier to manage. The installation documentation states that you only need the CREATE TABLES and CREATE PACKAGES privileges to install utPLSQL. However, this is not quite correct (at least for the version available when this article was written). You will also need to grant CREATE PUBLIC SYNONYM and EXECUTE on SYS.DMBS_PIPE to the schema into which utPLSQL is installed. To make this easier, I have written a script to create a utPLSQL owner schema with all the correct privileges. You can get this script on my website at: http://www.cda-llc.com/utplsql.htm. Listing 4 is an example of installing utPLSQL. STEP 3: CHOOSE PROGRAM TO TEST When you first start using utPLSQL you will most likely be creating unit test packages for existing packages that have already been developed. For your first foray into utPLSQL you should probably select a Listing 4. Installing utPLSQL
  • 7. DECEMBER 2003 ■ 1 1 ODTUG TECHNICAL JOURNAL fairly simple package. Starting with a simple package will let you create a complete unit test package fairly quickly and get you up to speed on the whole process. If you decide to adopt this approach as a standard, you will be creating unit test packages for all of your packages. Going forward, you will be creating the unit test packages at the same time as you are creating your programs. STEP 4: IDENTIFY TEST CASES Once you have chosen a package, you will have to come up with the test cases that need to be tested. Usually, the easiest way to do this is to think about what needs to be tested and come up with a table of expected results. When you are thinking about the test cases remember the following conditions: • Boundary conditions, especially parameters • Remember how NULL values should be handled • Remember “0” values For example, if we were developing unit tests for the simple PL/SQL example above (Listing 1), we might identify the inputs and expected results shown in Table 2. Notice that in my test cases I have included some NULLs and 0. This set is by no means exhaustive even for this simple function. Also, the result that you specify for a test case is not always obvious. I had to make a decision about how NULL and “0” values should be handled by the function. This is all part of the design, and in fact this table becomes the truest statement of the function design! STEP 5: BUILD A PACKAGE FOR THE TESTS Now we come to the main part of the work needed to implement the unit test. We have to build the actual PL/SQL unit test package that we will use to test our function. For this simple function, there are three procedures we must include in the UT package: UT_SETUP — The Unit Test setup procedure UT_TEARDOWN — The Unit Test teardown procedure UT_SALARY_MULT — The procedure to actually perform the unit test on SALARY_MULT Listing 5 shows the specification of our unit test package. The package is named “ut_EMPDEPT” because we have put the SALARY_MULT function into a package named EMPDEPT. In this simple case, UT_SETUP and UT_TEARDOWN don’t do anything, so they will look like Listing 6 in the package body. Even in cases where they don’t do anything, they still have to be created in the UT package so it will interface correctly with the utPLSQL utilities. Next, you will need to create the procedure that actually performs the unit test. This procedure must follow this naming standard: UT_<The name of the program to be tested> For example, the unit test procedure for this simple function would look like Listing 7. Next we have to add the “guts” of the procedure. You do this by using the utPLSQL assert API to assert the success or failure of each test case. p_input 1234 NULL 1234 NULL 0 1234 1234 p_multiplier 5 5 NULL NULL 5 0 -10 Result 1296 NULL 1234 NULL 0 1234 1111 Table 2. Example of Expected Results Listing 8. Specification for utAssert.eq Continued Listing 7. Unit Test Declaration for ut_SALARY_MULT Listing 6. When UT_SETUP and UT_TEARDOWN Is Not Used Listing 5. Specification of Unit Test Package
  • 8. ODTUG TECHNICAL JOURNAL 12 ■ DECEMBER 2003 Test Your PL/SQL Before You Write It! (Continued) There is a whole suite of functions and procedures in the utAssert package that you will use to do this. These routines allow you to easily test the outcome of your results, and report the results to utPLSQL. The results of all of the test cases are used by utPLSQL to determine the entire unit test outcome. Simplest Assert: utAssert.eq The utAssert.eq procedure is used to check for the equality of two scalar values. It can handle many data types: dates, strings, numbers, Boolean. If the two values passed are equal, it records the test as successful. If the values are not equal, then it records that the test fails. Listing 8 on page 11 is the specification of this assert. Where: msg_in = A message to be displayed if the assertion fails. check_this_in11 = The value to be checked against_this_in = The expected value null_ok_in = Specifies if NULL is allowed as an input parameter Listing 9 is an example of using utAssert.eq for one of the test cases listed above. This test case is labeled “Standard Execution” and it will see if a call to salary_mult with input parameters of 1234 and 5 will return 1296 as expected. STEP 6: TEST YOUR PROGRAM! Now let’s test the program with this simple test case. To do this, we use the test utility in the utPLSQL package, passing it the name of the package we are testing (“EMPDEPT” in this case). So we could run the test using the following command: SQL> EXECUTE utPLSQL.test(‘EMPDEPT’) An example of running this simple test is shown in Example 2. The big SUCCESS tells us that the entire unit test was successful. In the section titled “Individual Test Case Results” there will be a line for every test case indicating the results of the test. In this case, the test passed (SUCCESS), using the utAssert.eq procedure (the “EQ”). The label of “Standard Execution” is shown so that if a test fails you will know which test it is. Finally both the expected result and the actual result are shown. Now let’s add ALL of the tests in our test case table. This is a matter of simply adding additional asserts for the other test cases. The utPLSQL package keeps track of the overall testing status (i.e., did any tests fail?) and reports on the results. Listing 10 shows the unit test code for all of the test cases in Table 2 on page 11. Each call to an utAssert procedure has a test description or label (i.e., ‘p_input=NULL’ or ‘p_multiplier_pct is negative’) and the input parameters are specified based on the test cases we Example 2. Successful Call Unit Test of SALARY_MULT Listing 10. Unit Test Code for All Test Cases in Table 2 Listing 9. Example of Using utAssert.eq
  • 9. DECEMBER 2003 ■ 13 ODTUG TECHNICAL JOURNAL had identified before. The unasserted procedures will compare the output of the calls to the program being tested against the specified expected results. A New utAssert Procedure: isNull You will notice that two of the tests did not use utAssert.eq, instead they used utAssert.isNull. This is because, of course, since NULL does not equal NULL in Oracle, we have to handle NULLs differently. The utAssert.isNull procedure (see Listing 11) checks to see if the specified value is null. Where: msg_in = Same as before, a message to be displayed if the assertion fails. check_this_in = The value to be checked Notice that there is no against_ this_in! This is because it is not needed in this case, since all you are checking is if the specified value is NULL. There is also another related procedure called isNotNull that performs the opposite check. What Happens When The Test Fails? Now let’s run the full test (see Example 3). Oh no! The test failed! You can tell this by the big FAILURE written across your screen! But why did it fail? Looking at the test case results we can see that there were two specific test cases that failed. The first failed test case was labeled “p_multiplier_pct” and the function returned NULL instead of 1234 as was specified. The second failure did not even return the label because the test case resulted in an Oracle error! But we know that the “p_multiplier_pct=0” test case was run immediately after the “p_input = 0” test case, so we know this must be the one that failed. Notice that the last test case was not run due to the Oracle error. This happens when there are unhandled Oracle exceptions. In these cases, it may take a few iterations to get all of the tests to even run. (This example is why I used the weird algorithm). To finish the development of the function, we will have to fix these problems. The repaired function is shown in Listing 12 on page 14. Now when the test is rerun (see Example 4), everything is successful! Example 4. Successful Test After Repair Example 3. Failure of utPLSQL Test Listing 11. Specification of the isNull Assert Routine Continued
  • 10. 14 ■ DECEMBER 2003 ODTUG TECHNICAL JOURNAL GENERATING INITIAL TEST PACKAGES It is a lot of work to write these UT packages. To help with some of the routine work involved, utPLSQL provides you with some utilities that can generate much of the test packages for you. This makes it much easier to initially setup the UT packages. These utilities can generate skeleton UT packages that simply consist of the package specification and a package body with all the UT procedures defined, but with no unit tests in them. You would then add the specific unit tests to these skeleton packages. You can also pass the generator a data set and actually generate the code to check many or most of your test cases if they are simple enough. Listing 13 is an example of using a data set to generate your UT package. ONE UT PACKAGE PER APPLICATION PACKAGE Each UT package can test as many programs as you want. However, since most PL/SQL programmers group their programs into PL/SQL packages (as they should), it is usually the best practice to create one unit test package per application package. This is the way that the UT package generators work and it is almost assumed that this is the case in the utPLSQL code. Here is the package spec of an example application package (see Listing 14) along with the package spec of its UT package (see Listing 15). Test Your PL/SQL Before You Write It! (Continued) Listing 13. Using a Data Set to Generate a UT Package Listing 12. Repaired Function Listing14. Application Package to Test Listing 15. Associated Unit Test Package
  • 11. DECEMBER 2003 ■ 15 ODTUG TECHNICAL JOURNAL USING UT_SETUP AND UT_TEARDOWN We have not done much with ut_Setup or ut_Teardown yet. That is because our examples have been so simple that they did not need them. If you have more complicated test cases where you need to set up some data or modify package states before you can perform the unit test, you will have to use ut_Setup and ut_Teardown. The ut_Setup procedure is called before any of the unit test procedures in the UT package are executed. It needs to set up the data, package states, and expected result arrays for ALL of the unit test procedures in the package. The ut_Teardown procedure is called after all of the unit tests are performed. It should clean up any data that was used for the unit test as well as any data that might result from the unit test. It must also clean up any data that is left over as a result of a unit test Failure. For example, if the test is supposed to delete some data, you should add a deletion step to ut_Teardown to clean up the data if the deletion test fails. The unit test package should be completely autonomous. Ideally it should not rely on any application data already existing in the database. It should also leave the database in the exact state it was in before the tests were run. This needs to be done so that the tests can be run multiple times without the tester having to do any additional work. Listing 16 is an example of a simple use of the ut_Setup and ut_Teardown procedures. In this example, ut_Setup is doing two things: 1) Creating a record in a table that is supposed to be deleted during a test, and saving the Identifier for that record in a variable to be used by the test case. 2) Finding a non-existent Identifier to use for another test case. The ut_Teardown procedure is simply removing the record that was created in ut_Setup just in case the test fails. Listing 17 shows an example unit test using this setup and teardown. The empdept.rif call in this procedure uses the variable setup in ut_Setup to attempt an employee deletion. The next assert call tests to see if the deletion worked. If the test passes, then the record will be deleted and the system state will be the same as before. If the test fails, then ut_Teardown will cleanup the employee that was created for this test. More Assert Routines: utAssert.throws and utAssert.eqQueryValue You may have noticed that this example uses some more utAssert routines: utAssert.throws — This routine tests the specified PL/SQL to see if it raises the specified exception. In the examples above, the expected result is for the procedure to raise the NO_DATA_FOUND exception. This assert call will fail the test if that exception is not raised. utAssert.eqQueryValue — This routine tests the result of a specified query against an expected result. In this case, the SELECT COUNT query should return “0” if the call to empdept.rif succeeds. Continued Listing 18. Defining a Test Suite Listing 17. Unit Test Using Work Done in ut_Setup and ut_Teardown Listing 16. Using ut_Setup and ut_Teardown
  • 12. ODTUG TECHNICAL JOURNAL 16 ■ DECEMBER 2003 Test Your PL/SQL Before You Write It! (Continued) GROUPING TESTS INTO TEST SUITES Each UT package is a group of related unit tests, usually for a single application package. However, you can also group many of these UT packages into a larger group called a test suite. Once you do this, you can easily test the whole set of UT packages at once. If you put all of the application packages for your application into a test suite, you can perform a full regression test on your application’s server side code with a single command! Listing 18 on page 15 shows an example of defining a test suite. Once a test suite is defined, you can execute the entire test suite with a single command: SQL> exec utplsql.testsuite (‘plvision’); Using UT Packages for Regression Testing One big advantage of creating formalized automatic unit test programs is that it makes it very easy to do a comprehensive regression test when anything in the system changes. For instance, you might want to do a full regression test in the following situations: • Every build! — Run a full regression test with every build to make sure that the integration did not cause problems with (supposedly) non-modified code. • Oracle DB upgrade — Every time you upgrade the Oracle DB, there is the possibility of revealing defects in your system. Even a minor upgrade might “fix” a problem for which you had coded a workaround. If you have created these UT packages, it is easy to ensure that the DB upgrades did not change the behavior of your application. • Schema modifications — You should run the full regression test every time you make schema modifications. This will ensure that your schema changes did not cause defects in code. • Dependent system changes — Every time a dependent system changes, even if your application does not change, you can run the regression tests to make sure your system still works as expected. This is especially useful if you have integrated someone else’s PL/SQL utilities into your system. REGRESSION TEST EXAMPLE Let’s detail a simple example (see Listing 19) of how a regression test might catch a bug due to a schema change. Let’s say we have a routine in empdept named get_emp_name whose purpose is Example 6. Failure Because of Schema Change Example 5. Successful “Get Largest Name” Result Listing 19. Create an Employee Record
  • 13. DECEMBER 2003■ 17 ODTUG TECHNICAL JOURNAL to return the employee name given their ID. One of the tests we put into the unit test suite was a test to ensure that the function would retrieve the largest value possible in the table (a boundry condition). To do this, the following code was put into the ut_Setup routine: This setup code simply creates an employee record with the largest value possible in the ename column. The following test was put into the ut_get_emp_name routine: utAssert.eqQueryValue(‘Get Largest Name’ ,’SELECT ename FROM emp WHERE empno = ‘||v_empno_to_get ,empdept.get_emp_name(v_empno_to_get)); When run before the schema change, the result is shown in Example 5. The value for ename that was derived by the ut_Setup is “XXXXXXXXXX” because the ename column was a VARCHAR2(10) column. Now let’s make a schema change: ALTER TABLE EMP MODIFY ENAME VARCHAR2(50); If we run the test again (see Example 6), our results are different! This test now fails because the code had a variable specification hard coded as VARCHAR2(10), instead of using EMPDEPT.ENAME%TYPE. This is a fairly common defect that is introduced with such schema changes, which is why I used it as an example. How Can I Write the Unit Tests Before I Write the Code? To get the most benefit from this approach it is best to actually write your unit tests before you write your code. This may be a strange idea to some people who are thinking, “How can I know what to test until I write the code?” For many this approach will involve a big shift in the way they approach PL/SQL development. In order to write the unit tests you will have to think through everything your code is supposed to do before you write even one line of code! You will have to design your call interface, specify the parameters, and have detailed designs before you even start. This might seem difficult to some, but actually this “restriction” is one of the biggest benefits of this approach. If you actually code the unit tests first, you will be forced to think through your design, and will invariably have a better design before you start coding. You will also have fewer initial defects because of course you will write the code to handle all of the unit tests you have just coded. PROCEDURE Here is the overall procedure you will need to follow to write your unit tests before writing your program units: 1. Write package spec and empty program units. First, write your package specification and empty program units. This will give you a “compilable” shell that will allow you to write and compile your unit test packages. For example, the empdept.rif procedure might look like Listing 20. 2. Use the utGen package to generate your UT package. Now that you have your “shell” package, you can use the utGen package in utPLSQL to generate the structure of your UT package. 3. Identify your test cases. Next, you can identify the test cases you want to add to the UT package. 4. Add code to test each test case. Now go ahead and code the unit tests, ensuring that the UT code compiles. 5. Run the UT package to ensure it works. It will fail of course, because you have not yet written the code! 6. Now, actually write the code! Now write the code, which should be easier because you had to think about it while you were writing the unit tests! You should write small pieces of functionality, and ensure each piece passes its unit tests before continuing with other pieces. Run the UT package frequently to ensure that your code is written correctly. 7. When the UT package returns “SUCCESS”, you’re done! When you see the big SUCCESS, you know you have finished your program AND that you have written high quality code! IS THIS ALWAYS POSSIBLE? Is it actually possible to always write the unit tests first? Well, to be honest, it is not always possible to do this. There are certain situations where your application architecture or other constraints may prevent you from always approaching it this way. But if you start with this as your goal, you will be much better off than if you don’t even try. Continued Listing 20. Compilable Shell Before Tests Are Added Figure 2. Ounit Sample Screen
  • 14. ODTUG TECHNICAL JOURNAL 18 ■ DECEMBER 2003 Hurdles to Overcome Of course nothing is ever as easy as it seems at first (if this even seems easy for you). If you really want to do this there are some challenges you will have to overcome: • Writing the UT packages can take as long (or longer) as writing the code. But as I said before, I think it’s really worth it in the long run. This is just something that you will have to get used to. • Your testing process will have to change! For many organizations change can be difficult. Especially if you really want to do this but are not in the position to mandate it. • Developers may resist the change. Many developers may think that this sort of testing is overkill, and may fail to see the value in it. If possible, try to convince your whole team that this is the right approach. It is much easier to affect change if everyone agrees that this is the way to go. • There is no nice UI. Currently there is no user friendly UI for utPLSQL. This may change in the future; I know that Quest software had considered adding a front end to utPLSQL to one of their packages, though I don’t know the status of that at this time. Also, Michael O’Neill has developed a Web PL/SQL UI for utPLSQL, but I have not looked at it yet. It’s available at: http:// sourceforge.net/projects/plcodebrew Ounit — A GUI Front End to utPLSQL If you are wondering if there are some nicer GUI tools that would support this unit testing approach, you are not alone. In fact, Steven Feuerstein and Patrick Barel have teamed up to develop a nice GUI front end. Figure 2 on page 17 is an example screenshot. This program is called Ounit, and version 1.0 is currently available for download at http://www.ounit.com This program is currently free. Measuring Unit Test Code Coverage with DBMS_PROFILER When you have written your unit tests, you may wonder if you have actually written good unit tests! How can you know this? Well, mostly you will know based on your experience. However, one unit test quality metric you can actually calculate is how much of your code is actually tested by your suite of unit tests. This can be called a “Code Coverage” metric for your unit tests. To do this, you would use the utilities in Test Your PL/SQL Before You Write It! (Continued) Listing 23. SQL Script to Report Results Listing 22. Saving Statistics in plsql_profiler Tables Listing 21. Script to Accumulate PL/SQL Statistics Listing 24. Code Coverage Report
  • 15. ODTUG TECHNICAL JOURNAL DECEMBER 2003 ■ 19 the DBMS_PROFILER package to accumulate statistics about your executed PL/SQL code while you are running your unit tests. You can then use these statistics to run a report that shows you how much of your PL/SQL code was actually executed by your tests. If you don’t have 100 percent of your code executed, then either you are missing some test cases you should have, or you have orphaned code. Here is an example of using DBMS_PROFILER to perform a code coverage test: 1) First, accumulate the PL/SQL statistics using a script like that shown in Listing 21. 2) The statistics from your test run will now be saved in the plsql_profiler tables (see Listing 22). 3) Listing 23 shows a SQL script that reports the results. 4) Listing 24 shows an example of running this report for the example package used in this article. This report tells me that my test cases only actually executed around 30 percent of the code in my package! I guess I have a few more test cases to write. To find out more about DBMS_PROFILER, including how to install it in your environment, look in the Oracle Supplied PL/SQL Packages Reference in the Oracle Documentation. Conclusion It is my opinion that the utPLSQL approach is well worth the effort and will lead to much better quality PL/SQL code. It will encourage better code design, increased modularity, and a more repeatable testing process. In the long run it will lead to lower development costs because of the reduced number of defects, which are expensive. And you even get to say you used an XT practice! It is my intention to encourage the use of this approach for ANY new PL/SQL project that I am involved with. Happy Testing! About the Author Ken Atkins is a cofounder of Creative Design Associates (www.cda-llc.com), a consultancy that focuses on Oracle Designer, SCM, Project Management, and Oracle Development Tools. He has more than 12 years of experience developing applications with the Oracle Database and tools. Ken is a popular presenter at national Oracle conferences, and has been active in ODTUG for over seven years, including a term on the ODTUG Board of Directors. He is also a coauthor of Oracle Designer System Generation (Oracle Press). Ken maintains an Oracle tip site at: http://www.arrowsent.com/oratip. If you have any questions or comments about this article, you can e-mail Ken at [email protected]. You can download this paper as well as other papers at www.cda-llc.com. Let Us Show You How! JUNE 20-24, 2004 THE WESTIN KIERLAND RESORT & SPA SCOTTSDALE, ARIZONA 910.452.7444 www.odtug.com