0% found this document useful (0 votes)
68 views69 pages

Unit Testing Database Applications

The document discusses unit testing database applications. It introduces the DBMSUnit test framework, which addresses problems with existing unit test frameworks when testing database applications. DBMSUnit handles coupling between test methods due to database dependencies and persistence issues by managing the state of the database between test executions. It also accounts for the three-valued logic of databases where results can be true, false, or unknown.

Uploaded by

raviontestedge
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
68 views69 pages

Unit Testing Database Applications

The document discusses unit testing database applications. It introduces the DBMSUnit test framework, which addresses problems with existing unit test frameworks when testing database applications. DBMSUnit handles coupling between test methods due to database dependencies and persistence issues by managing the state of the database between test executions. It also accounts for the three-valued logic of databases where results can be true, false, or unknown.

Uploaded by

raviontestedge
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 69

Unit Testing Database Applications

Claus A. Christensen Steen Gundersborg Kristian de Linde Kristian Torp


{cac, earser, kdl, torp}@cs.aau.dk

Department of Computer Science Aalborg University & Logimatic Software A/S

Outline - Overall
Testing in general Unit testing
The xUnit family of unit test frameworks

Database applications
A table wrapper example

Unit testing database applications


What is wrong with the current unit test frameworks The DBMSUnit test framework

Experiences using DBMSUnit


Based on experiences from Logimatic Software A/S

Finding more information on software testing Conclusions


Future work
Livslang Lring 20. august 2004 2

About Myself
Education
Master in computer science (database systems) 1994 Ph.D. in computer science (database systems) 1998

Work four years in software industry


Three years at Logimatic Software A/S

Currently associated professor, Database and


Programming Systems Unit, Aalborg University Research interests
Programmatic access to databases XML and databases Moving objects and databases
Livslang Lring 20. august 2004 3

My Road to Working with Software Test


By introducting big enough errors in released software Trying to increase quality of work Software developed may contain severe errors
Missing sleep and bad nerves Unsatified customers

Unable to understand existing code


Written by morons

Questions from management


Does it run? Is it error-free?

Afraid to make changes to existing code Nice emails from the open source community
Livslang Lring 20. august 2004 4

Disclaimer

Livslang Lring 20. august 2004

[Courtesy: Tom Kyte]

Outline - Testing in General


Motivation Purpose of test Types of tests

Livslang Lring 20. august 2004

Why Focus on Test?


The importance of software testing and its
implications with respect to software quality cannot be overemphasized M. Deutch

Error removal is the most time-consuming phase of a


[software] life cycle R. Glass.
20% analysis, 20% design, 20% implementation, 40% test

Current available positions at Microsoft (2004-08-19)


Software development Software testing
Livslang Lring 20. august 2004

556 304
7

Test Purpose
Test of performance
TPC*C, TPC*H, TPC*R, and TPC*W (www.tpc.org) Home-grown benchmarks
N

90% all user requests finished within a minute

Test of design or idea


Prototyping

Test of correctness
Formal verification Code reviews and walk-throughs Compile-and-run Stocastic testing (n-solutions) Unit testing
Livslang Lring 20. august 2004 8

Unit, Integration, and System Tests


A Need Finished System Success Requirements Failures System Test Success High-Level Design Failures Integration Test Success Low-level Design Failures Unit Test

Code
Livslang Lring 20. august 2004

[source http://www.stsc.hill.af.mil/stscdocs]

Unit, Integration, and System Tests, cont.


System Test
Testing overall requirements to the system Does the system works as a whole?

Integration Test
Testing of interfaces between subsystems How well do the subsystems fit together?

Unit test
Testing a single unit (or module) of code Uses stubs or drivers for interfaces to other units Is the foundation working?
Livslang Lring 20. august 2004 10

Outline - Unit Testing


Motivation for
unit testing JUnit

The xUnit family The JUnit test framework


A framework for Java

Extensions to JUnit

Livslang Lring 20. august 2004

11

Motivation for Unit Testing


The single most effective technique to better code! Very simple [and cheap] to get started
Return On Investment very high

Test code very informative to read


Internal and informal documentation End-users typically use code snips in documentation as an outset for development!

Supports incremental development


System can be fully tested frequently, e.g., each night

Better motivated for writing test cases if these are


intensively used.
Livslang Lring 20. august 2004 12

Motivation JUnit
It is nearly impossible to do a good job at software
error removal without tool support Used as model for many other unit test frameworks Instant binary feedback to developers Easy to use Widely used (even students use it, under pressure!) Open source (and free)
There are many extremely expensive commercial products related to software testing

Itegrated into many IDEs


Eclipse, Idea, JBuilder, JDeveleoper, jEdit, etc.

Written by very compentent people


Kent Beck and Eric Gamma
Livslang Lring 20. august 2004 13

Unit Test Characteristics


Supports Code a little, test a little development
analysis
start project

design

imp.

test
stop project

start project

stop project

Done by programmers, for programmers! Not a formal validation and verification of a program!

Livslang Lring 20. august 2004

14

The xUnit Family


JUnit (Java, master copy) **
http://junit.org/

nUnit (all .Net languages)


http://nunit.org

PerlUnit (Perl)
http://perlunit.sourceforge.net/

PyUnit (Python)
http://sourceforge.net/projects/pyunit/

RubyUnit (Ruby)
http://www.ruby-lang.org/

utPLSQL (Oracles PL/SQL) **


http://utplsql.sourceforge.net

Unit++ (C++)
http://unitpp.sourceforge.net/

VBUnit (Visual Basic, commercial product)


http://www.vbunit.com
Livslang Lring 20. august 2004 15

The JUnit Test Framework


Software framework
Inversion of control (fill in the blanks programming) Do not call us, we will call you!

The basic test class is TestCase


TestCase run(TestResult) runTest() setUp() tearDown()

Supplied by JUnit

MyTestCase setUp() tearDown() testM1() testM2()

Supplied by programmer
16

Livslang Lring 20. august 2004

The JUnit Test Framework, cont


Three import concepts in JUnit
Test suite Test case Test method

Test Suite

Test Case

Test Method

Livslang Lring 20. august 2004

17

The setUp and tearDown Methods


public class TestHardDrive extends TestCase{ private HardDrive seagate1; private HardDrive seagate2; /** Sets up the test fixture. */ protected void setUp(){ seagate1 = new HardDrive("Seagate", "Deskstar", 1000.00, 40); seagate2 = new HardDrive("Seagate", "Deskstar", 1000.00, 40, Storage.GB); }

/** Tear down the test fixture */ protected void tearDown(){ // empty } }
Livslang Lring 20. august 2004 18

The Test Methods


public class TestHardDrive extends TestCase{ <snip> /** First test method */ public void testIntel1(){ assertEquals("Make not equal", seagate1.getMake(), "Seagate"); assertTrue("Price not equal", seagate1.getPrice() == 1000.00); }

/** Second test method */ public void testEquals(){ assertTrue("HardDrives are not equal", seagate1.equals(seagate2)); <snip> } }
Livslang Lring 20. august 2004 19

Overview JUnit Test Framework

Livslang Lring 20. august 2004

[Source: www.junit.org]

20

Consequences of using Unit Tests


Refactoring code becomes much easier
cost cost

time

time

Without unit tests

Using unit tests

Have more KLOC test code than real code Makes your low-level code much more reliable!
Solid foundation for integration and system tests

Decrease the use of a debugger


A debugger is a review tool not a test tool!
Livslang Lring 20. august 2004 21

JUnit Extension
Test coverage
Clover (commercial) http://www.cenqua.com/clover/ NoUnit (open source) http://sourceforge.net/projects/nounit/

MockObjects
MockMaker http://mockmaker.sourceforge.net EasyMock http://www.easymock.org

Performance testing
JUnitPerf http://www.clarkware.com/software/JUnitPerf.html Daedalos http://www.daedalos.com/EN/djux

Database testing
DBUnit http://dbunit.sourceforge.net/
N

Import/export oriented. Truncates tables!

Most extensions use the Decorator Design Pattern


Livslang Lring 20. august 2004 22

Outline - Database Application


An example
table wrapper API

Overview of interfaces provided by table wrapper API The wrapper in an application stack

Livslang Lring 20. august 2004

23

A Table Wrapper API


Features illustrated using Java
getAttribute(<id>) return String

Livslang Lring 20. august 2004

Table 1 Table 2

setAttribute(<id>, String) count() return int exist(<id>) return boolean

equal(<id> 1, <id> 2) return boolean update(<id> , values) return boolean delete(<id>) return boolean id exist(<id>) return boolean id

24

Examples of Wrapper Interfaces


Table
list(<predicate>) getName(<id>) setName(<id>)

update( list <id>, list values)

get(<id>) update(<id>, values)

Livslang Lring 20. august 2004

25

Table Wrapper in Application Stack


Web-services XML API

Views

Tables

Table wrapper API more advanced than CRUD


For example Hibernate (http://www.hibernate.org/) and Cayenne (http://objectstyle.org/cayenne/) Customized for each single table
Livslang Lring 20. august 2004 26

Outline - DBMSUnit
Motivation
Problems existing frameworks

Test framework design and implementation


Static structure Test framework design Dynamic structure via sequence diagrams

Extensions Integration with utPLSQL unit test framework Oracle specifics

Livslang Lring 20. august 2004

27

Testing seen from 30.000 Feet


input

Environment

System Under Test

output

Testing functions (input/output) Testing procedures (side effects)


Livslang Lring 20. august 2004 28

Problems Existing Unit Test Framworks


Coupling between test methods
Test methods are independent must always build test fixture Foreign keys in a database context

Persistency
Focus on main memory data structures Side effects (procedures not functions) Manual clean up between executing test cases necessary

Two-valued logic
In a database context three-valued (true, false, and unknown)
Livslang Lring 20. august 2004 29

A Sample University Schema


Name StudentID Name Date CourseID SemID

SemID

Student k

Participant

Course h

CPR 1 Semester 1

SemID

StartDate

EndDate

Livslang Lring 20. august 2004

30

Database Application Test Framework


Coupling between
Test methods Test cases

Dependent of the state of the database Persistency


Must test for side effects Must clean up after use

Livslang Lring 20. august 2004

31

Coupling Between Test Methods


Setup only executed once for each test case
Also done by some JUnit extensions Reason: speed it takes milliseconds to a create database connection JUnit DBMSUnit Framework
setup() test_1() teardown() setup() test_n() teardown()

Test Case

Framework
setup() test_1() test_n() teardown()

Test Case

Livslang Lring 20. august 2004

32

Coupling Between Test Methods, cont.


Test methods are no longer independt
Must be executed in a specific order!
public class MyTestCase extends TestCase{ // insert rows into underlying table(s) public void testInsert1(){ } public void testInsert2(){ } // query and update rows inserted public void testUpdate1(){ } public void testQuery1() { } public void testQuery2() { } public void testQuery3() { } // delete rows from underlying table(s) public void testDelete2(){ } public void testDelete1(){ } }
Livslang Lring 20. august 2004 33

default order of execution

Coupling Between Test Cases


To test student a valid semesterID must exist To test course a valid semesterID must exist To test participant a valid courseID and studentID must
exist Reasons
Controllability Simpler to build text fixture Participant Student Course

Semester
Livslang Lring 20. august 2004 34

Building Test Fixtures in JUnit


Single table
public void setup(){ // semester table insert(row1) insert(row2) }

Two tables
public void setup(){ // semester table insert(row1) insert(row2) // course table insert(row3) insert(row4) }

We want to avoid the repetition of code in the setup


methods
Livslang Lring 20. august 2004 35

Coupling Between Test Cases, cont.


Test suite JUnit Semester Student Course Participant

Participant Student Test suit DBMSUnit Course Semester Time


Livslang Lring 20. august 2004 36

Static Structure of Test Case


JUnit
TestCase setup() teardown()

DBMSUnit
TestCase setup() teardown() use() disuse() TestSemester semesterId = sm47 NotSemesterId = sm99 prerequests = null test1() test2() test3()

TestSemester test1() test2() test3()

Livslang Lring 20. august 2004

37

Static Structure of Test Case, cont


TestSemester semesterId = sm47 notSemesterId = sm99 prerequests = null test1() TestStudent semesterId = TestSemester.semesterID studentId = St43 prerequests = TestSemester test1()

TestCourse semesterId = TestSemester.semesterID courseId = Co343 prerequests = TestSemester test1()


Livslang Lring 20. august 2004

TestParticipant semesterId = TestStudent.semesterID studentID = TestStudent.studentID courseID = TestCourse.courseID prerequests = TestCourse, TestStudent test1()
38

Dynamic Structure of Test Case


Setup method
Responsible for setting up the text fixture

Teardown method
Responsible for tearing down the text fixture

Use method
Responsible for make the public variables exist in the test database.

Disuse method
Responsible for make the public variables non-existing in the test database.

Run method (called by developer)


Calls all test methods in specified order
Livslang Lring 20. august 2004 39

Avoiding Repeated Setups


If we test participant the setup method of semester is
called twice
If both calls inserts data then it leads to integrity constraints violations Participant Student Course

Semester

Livslang Lring 20. august 2004

40

The Test Stack


Controls that setup method is only executed once for
each test case in a test session Controls the clean-up of the database Singleton design pattern
only one Stack object (connected to database table)
Test Case Public constants run() setup() teardown() use() disuse() test1()
Livslang Lring 20. august 2004

Stack push(TestCase) TestCase pop() TestCase top() isActive(TestCase) cleanup(TestCase)

41

Setup and Teardown Methods


void setup() // setup what this test case depends on for unit_test in prerequests unit_test.use() // tell that test case is in use stack.push(self) // setup not part of any test method <snip>

void teardown() // own teardown not part of any test method <snip> // tell that test case is longer in use stack.pop() // teardown what this test case depends on for unit_test in reverse(prerequests) unit_test.disuse()
Livslang Lring 20. august 2004 42

Use and Disuse Methods


void use() // setup myself self.setup() // make public variables legal testInsert1() // reuses insert test methods testInsertN()

void disuse() // make public variables illegal testDeleteN() testDelete1() // teardown myself self.teardown()
Livslang Lring 20. august 2004 43

The Goal of the Test Framework


Easier to build test fixtures
Extensive reuse between test cases

Minimal number of restrictions on application


developer in test methods
None
N

Insert, update primary key Select, update other than primary key (on specific data) Insert specific primary keys, update (on specific primary keys)

Slight modification
N

Trade-off
N

We must be able to clean up


Truncating tables is not an option!
Livslang Lring 20. august 2004 44

Setup Sequence Diagram


P:run()
setup()

P St C Se Stack

Participant
use()

Course
use() use()

Semester

Student

use()

test1()

Livslang Lring 20. august 2004

45

Teardown Sequence Diagram


P:run() Participant Course Semester

P St C Se Stack

Student

teardown() disuse() disuse() disuse() disuse()

Livslang Lring 20. august 2004

46

Requirements to Users
Must publish keys
Inserted in underlying table(s) Updated in underlying table(s) Optional keys guaranteed not to be in underlying table(s)

Must comply with rules for modification Specific order in which test methods are executed
Defaults to the textual order of the file

Must specify test cases that are prerequested

Livslang Lring 20. august 2004

47

DBMSUnit Extension
Support multiple users running tests concurrently
Goal: Speed up execution of large test suites

Avoiding repeated setups


Goal: Speed up execution of large test suites

Livslang Lring 20. august 2004

48

Supporting Multiple Users


Testing large applications Testing non-connected concepts
Student Course

Extensions

Semester

Stack user, time to live, being tested, being setup Locking

Livslang Lring 20. august 2004

49

Avoiding Repeated Setups


Minimize testing time Ordering of unit tests
Directed acyclic graph Topological sort

Teardowns Large schemas

Student

Course

Semester

Livslang Lring 20. august 2004

50

Integrating with utPLSQL


Benefits
Assert library Large user community

Extensions
Setup and teardown methods must be redefined Stack must be added Requirements must be followed
N

Cannot be checked by compiler!

Livslang Lring 20. august 2004

51

Oracle Specifics
Flashback queries
Multi-transaction rollback Ensures that flash back is to a consistent database state Removes the need for the teardown methods
N

Database garbage collection

Workspace management
CVS-like multiple versions of rows Saves changed rows to private copy of the database
N

Private to the user that changed the rows Public to all users of the database

Checks-in rows to shared database


N

Allows multiple users to run concurrently


Livslang Lring 20. august 2004 52

The Framework Offers


A systematic way of testing a database applications Automatic cleanup after testing
System failure Error in unit test

Minimal effort to build test fixture


Data only inserted once!

Simple to use
Looks-and-feel of existing xUnit frameworks

Livslang Lring 20. august 2004

53

Outline - Experiences
Overall experiences
The technical side The human side

Test patterns
Ideas for how to unit test database applications

Livslang Lring 20. august 2004

54

Experiences
It is non-trivial to get the test framework to work! The first unit test takes a long time to get the up and running due
to dependencies Building unit tests takes quite a long time and is repetitious in nature (reads boring)
Auto-generation can make it more interesting

When unit test first build, repeated execution is very simple! Good error messages are essential for quickly finding the test
methods (and test case) that failed. Ripple effects could not be avoided due to coupling between test methods and test cases!
However, not that hard to find the source of the error

Brute-force method for cleaning-up the database is nice to have


can be difficult to build, due to integrity constraints
Livslang Lring 20. august 2004 55

Experiences, cont.
It is important that the test cases can use the data that is
delivered with the database application.
Can be modelled with public variables (and no insert methods)

Invariants are good for detecting that an error occurred but not
which error
As an example, a simple count on the number of rows in a table

Encapsulate all calls to the system clock such that the time can
be frozen and the test always be done at a specific time.
Should also be applied to random value function Mock objects can be used for this

A simple coverage analysis is better than none!


All method testes at least once? However, remember to test for behavior not method

Livslang Lring 20. august 2004

56

Experiences, cont.
It is important to separate test code from the real
code. Symmetric methods are a thrill to test (high testability)
e.g., object2String, string2Object

Stocastic testing using trace files are not worth the


effort. We made changes more aggressively and later in the project than usual. Do not return values from test methods
There is nothing to use it for

Use dynamic SQL where possible!


May lead to hard-to-find errors in the code
Livslang Lring 20. august 2004 57

Experiences - The Human Side


The technique is fairly easy to learn
If knowledge of, e.g., JUnit before hand then even simpler!

Test cases should not be used for building permanent


test databases Manager : Does the work work? Developer: Yes!

Livslang Lring 20. august 2004

58

Test Patterns
Minimal/maximal pattern
Minimal case only the required attributes specified Maximum case all the attributes specified

NULL pattern (the ugly face of three-valued logic)


Replace all the attribute in minimum case with NULL values one by one

Repeat pattern
Run the insert test methods twice, should raise exception Run the copy test methods twice, should raise exception

Commit pattern
Execute all test method in a single transaction Execute each test method in a separate transactions
Livslang Lring 20. august 2004 59

Future Work

Stepping through the execution of each test method Fully integration with the utPLSQL framework Making DBMSUnit a JUnit extension Performance measurements on proposed performance improvements

How to use test methods for program documentation

Livslang Lring 20. august 2004

60

Finding More Information


comp.software.testing FAQ, good place to start
http://www.faqs.org/faqs/software-eng/testingfaq/preamble.html Danish site dedicated to software test http://www.softwaretest.dk/ Better Software magazine http://www.stickyminds.com/BetterSoftware/magazine. asp Softwaretest - kom godt i gang med testen, booklet, Poul Staal Vinje og Klaus Olsen, Dansk IT, 2004.

Livslang Lring 20. august 2004

61

Finding More Information, cont.


Robert Glass Facts and Fallacies of Software
Engineering, Addison-Wesley, ISBN 0-321-11742-5
Good introduction and arguments. No low-level details.

David Astels, Test-Driven Development A Pratical


Guide, Prentice-Hall, ISBN 0-13-101649
Overview of various unit test framework and very large example. Covers unit test of GUIs.

Glenford Myers, The Art of Software Testing, John


Wiley & Sons, 1979, ISBN 0-471-04328-1 (2nd Edition ISBN: 0-471-46912-2)
Easy to read and quite pragmatic.

Boris Beizers, Software Testing Techniques Van


Nostrand Reinhold, 1990 ISBN: 0-442-24592-0
Livslang Lring 20. august 2004 62

Reklameblok

Modelbaseret test
Vejen til mere effektiv test
Fr. Bajers Vej 7E Rum B2-109 Tid: Onsdag 25. august 13.00 16.00 http://www.ciss.dk

Livslang Lring 20. august 2004

63

Conclusion
Unit testing
is an inexpensive test approach is very helpful in software maintainance phase. can be the difference between success and fiasko

There is no single best approach to software error


removal R .Glass With respect to testing tools one-size-fits all does not apply! DBMSUnit is better for testing database than JUnit!
Can you live with dependencies between test cases and test methods?
Livslang Lring 20. august 2004 64

Stable requirements Accurate estimates


Livslang Lring 20. august 2004 65

JUnit Screenshot

Livslang Lring 20. august 2004

[Source: www.junit.org]

66

Two Concrete Test Examples


University example schema Semester test example
Single table

Student test example


Dependent tables

Livslang Lring 20. august 2004

67

Semester Test Example

Semester
SemID

1 2

Se Stack

Semester procedure run begin setup(); test_insert(); test_update(); test_exist(); teardown(); end;
Livslang Lring 20. august 2004

procedure test_insert setup test_update teardown test_exist begin update(SemID, SemID_update); if (exist(not_SemID)) then stack.push(); delete(SemID_update); insert(SemID); raise not_not_found_exception; public if delete(SemID); (not constant SemID := 1; then end if; exist(SemID_update) public commit; raise constant SemID_update:= 2; if (not update_not_found_exception; exist(SemID)) then end; end if; not_found_exception; public stack.pop(); constant notSemID := 3; raise end; end if; end;
68

Student Test Example

Student
SID SemID

Semester
SemID

St Se Stack

Student
procedure run begin setup(true); test_insert(); teardown(); end;

procedure teardown setup procedure procedure test_insert begin begin begin semester.setup(false); delete(SID_update); insert(SID, semester.SemID); stack.push(); delete(SID); public constant SemID := 1; commit; if (not exist(SID, semester.SemID)) then public constant SemID_update:= 2; stack.pop(); raise not_found_exception; public constant notSemID := 3; semester.teardown(false); end if; end; end; end;
69

Livslang Lring 20. august 2004

You might also like