Dbunittest PDF
Dbunittest PDF
Dbunittest PDF
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
Success
Requirements Failures
System Test
Success
Failures
High-Level Design Integration Test
Success
Failures
Low-level Design Unit Test
Code
Livslang Lring 20. august 2004 [source http://www.stsc.hill.af.mil/stscdocs] 9
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?
start stop
project project
start stop
project project
run(TestResult)
runTest() Supplied by JUnit
setUp()
tearDown()
MyTestCase
setUp()
tearDown() Supplied by programmer
testM1()
Livslang Lring 20. august 2004
testM2() 16
The JUnit Test Framework, cont
Three import concepts in JUnit
Test suite
Test case
Test method
Test
Test Suite Test Case
1 n 1 m Method
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/
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
setAttribute(<id>, String)
count() return int
exist(<id>) return boolean
get(<id>)
update(<id>,
update( values)
list <id>,
list values)
XML
API
Views Tables
System
Environment Under
Test
output
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)
Name
n m
SemID Student Participant Course
k h
CPR
Semester
1 1
test_1() test_1()
teardown() test_n()
setup() teardown()
test_n()
teardown()
Student Course
Semester
Semester Course
Test suite
JUnit Student Participant
Participant
Student
Test suit
DBMSUnit Course
Semester
Time
Livslang Lring 20. august 2004 36
Static Structure of Test Case
JUnit DBMSUnit
TestCase TestCase
setup() setup()
teardown() teardown()
use()
disuse()
TestSemester TestSemester
test1()
test2() semesterId = sm47
test3() NotSemesterId = sm99
prerequests = null
test1()
test2()
test3()
test1() test1()
TestCourse TestParticipant
semesterId = TestStudent.semesterID
semesterId = TestSemester.semesterID
studentID = TestStudent.studentID
courseId = Co343
courseID = TestCourse.courseID
prerequests = TestSemester
prerequests = TestCourse, TestStudent
test1() test1()
Participant
Student Course
Semester
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()
setup()
use()
use()
use()
use()
test1()
teardown()
disuse()
disuse()
disuse()
disuse()
Student Course
Semester
Extensions
Stack user, time to live, being tested, being setup
Locking
Semester
Extensions
Setup and teardown methods must be redefined
Stack must be added
Requirements must be followed
Cannot be checked by compiler!
Modelbaseret test
Vejen til mere effektiv test
Accurate estimates
Semester
SemID
Se
1
2 Stack
Semester
procedure run procedure test_insert
setup
test_update
teardown
test_exist
begin begin
update(SemID, SemID_update);
if (exist(not_SemID)) then
setup(); stack.push();
delete(SemID_update);
insert(SemID);
raise not_not_found_exception;
test_insert(); public
if
delete(SemID);
end(not
if; exist(SemID_update)
constant SemID := 1; then
test_update(); public
commit;
ifraise
(not update_not_found_exception;
constant SemID_update:=
exist(SemID)) then 2;
end;
test_exist(); end if; not_found_exception;
public
stack.pop();
raise constant notSemID := 3;
teardown(); end;
end if;
end; end;
Student Semester St
SID SemID SemID
Se
1 1 1 Stack
Student
procedure run procedure teardown
setup
procedure
procedure test_insert
begin begin
setup(true); begin
begin
semester.setup(false);
test_insert(); insert(SID, semester.SemID);
delete(SID_update);
stack.push();
teardown(); delete(SID);
end;
public constant SemID := 1;
if (notconstant
commit;
public exist(SID, semester.SemID))
SemID_update:= 2; then
raiseconstant
not_found_exception;
stack.pop();
public notSemID := 3;
end if;
semester.teardown(false);
end;
end;
end;