You are on page 1of 56

TDD with DbFit and Oracle

Writing readable, easy to maintain unit and integration tests for database code
Yavor Nikolov BGOUG Conference, 2013-05-18

Agenda
Concepts (Testing, Test-Driven Development) DbFit Demo

#bgoug2013

2/56

What is a legacy system?
You spot an obvious design problem know how to improve that, but the thought about consequences gives you a stomach ache.

source: Gojko Adzic, "Fighting the monster"

#bgoug2013

3/56

source: http://lisacrispin.com/2011/11/08/using-the-agile-testing-quadrants

#bgoug2013

4/56

Why (automated) testing?
Makes application change easier Safety net - provides confidence/removes fear Documentation Help to localize where exactly a defect is located Reduce the chance of new bugs Automation enables earlier feedback, saves time, helps focusing on solving the main problem. (Not everything is feasible to automate)

#bgoug2013

5/56

Test Fixture All the things we need to have in place in order to run a test and expect a particular outcome The test context #bgoug2013 6/56 .

System Under Test (SUT) The system that is being tested #bgoug2013 7/56 .

Arrange (set up the Fixture) 2.Test execution cycle 1. Assert (verify results are as expected) 4. Act (exercise the System Under Test) 3. Tear Down the fixture (to isolate other tests from this one) #bgoug2013 8/56 .

Unit test Tests small individual unit (module. procedure/function) In isolation (no interaction with other units) Should run quickly (otherwise people won't run them) #bgoug2013 9/56 .

Integration test Tests several modules as a group Slower than unit tests (usually) #bgoug2013 10/56 .

At least modeled and possibly even written by the customer End-to-end (slower than Integration & Unit tests) #bgoug2013 11/56 .Acceptance test Conducted to determine whether or not a system satisfies its acceptance criteria and to enable the customer to determine whether or not to accept the system.

Regression tests (Regress vs progress) Performed to make sure that previously working functionality still works after changes elsewhere in the system #bgoug2013 12/56 .

Refactor Is the the process of changing a system in such a way that doesn't alter external behaviour and improves it's internal structure (design) through small steps Doing refactoring without tests is unsafe #bgoug2013 13/56 .

TDD Cycle source: Internet #bgoug2013 14/56 .

Tests are not the main product in TDD TDD is a design technique The design emerges in small steps #bgoug2013 15/56 .

Why test first? Start with end in mind (think from point of view of caller) This perspective helps for better design Test coverage is useful byproduct Greatly reduces the need of debugging #bgoug2013 16/56 .

Cost of change (traditional) #bgoug2013 17/56 .

Cost of change (test early) #bgoug2013 18/56 .

data held in DB are the most vital commercial asset they have Business critical functions rely on this data So it makes sense to validate that data is stored and processed correctly #bgoug2013 19/56 .Why testing the Database? For lot of businesses.

.Challenges of Database testing. Constraints Attitude ("it's not my job") #bgoug2013 20/56 .. Bad tools Too much boilerplate code OO tools not directly applicable for RDBMS Inherently hard to test. Isolation is difficult Changes are persistent Shared environment Triggers.

clean up after tests #bgoug2013 21/56 .How to isolate db tests? Run tests in one transaction Makes them repeatable and independent When one transaction is not an option .

avoid running tests on top of production #bgoug2013 22/56 .How to isolate db tests (2)? Dedicated database One db per contributor Separate schemas Shared Dev db may work too As a rule .

Other Tips Make tests self-sufficient Don't count on the order of tests Prepare everything you need for the test in its set-up #bgoug2013 23/56 .

DbFit #bgoug2013 24/56 .

com/benilovj/dbfit #bgoug2013 25/56 .What is DbFit? Initially created by Gojko Adzic: to enable efficient database testing motivate database developers to use an automated testing framework Enables manipulating database objects and defining tests in tabular form Open source https://github.

DbFit. FIT is Acceptance testing framework customer oriented tests are described as tables FitNesse is Wiki-web based front-end for FIT #bgoug2013 26/56 . FIT and FitNesse DbFit is based on FIT+FitNesse+DB Fixtures which enable FIT/Fitnesse tests to execute directly against a database.

FitNesse architecture source: Fittnesse User Guilde .One Minute Description #bgoug2013 27/56 .

and the system under test (e.What is DbFit Fixture? A fixture is interface between: the test instrumentation (Fit framework).g. test cases (Fit tables). a database stored procedure) In general there is 1:1 mapping between Fit table and fixture #bgoug2013 28/56 .

Why DbFit? Easy to use (even for non-technical people) Tests expressed and managed as tables Web-Wiki front-end Provides all the plumbing: Transaction management Features based on meta-data Parameter mapping Runs inside FitNesse .already integrated with lots of other tools/libraries #bgoug2013 29/56 .

What is Wiki? The simplest online database that could possibly work. .cgi?WhatIsWiki #bgoug2013 30/56 .Ward Cunningham Allows users to freely create and edit Web page content using any Web browser A group communication mechanisms Encourages democratic use of the Web and promotes content composition by nontechnical users source: http://wiki.org/wiki.

SuiteSetUp. PageFooter SetUp. Test.UserGuide #bgoug2013 31/56 . Test Suites Page types . TearDown. can be overriden http://fitnesse. SuiteTearDown Inherited recurively by default.org/FitNesse.Suite.SubWiki.Fitnesse Wiki Hierarchies . Static Some special pages: PageHeader.

2. Set up the input data (arrange). Execute a function or procedure (act). Run a query and compare actual vs expected data (assert). 3.A Unit test with DbFit 1. #bgoug2013 32/56 .

Basic commands of DbFit Query Insert Update Execute Procedure Execute #bgoug2013 33/56 .

tables.Advanced features Inspect queries. procedures to auto-generate test tables and regression tests Store and compare queries Standalone mode for full control #bgoug2013 34/56 .

Download: http://benilovj.Getting started 1.sh or startFitnesse.jar) to lib subfolder 5. Run the startup script (startFitnesse.http://localhost:8085 #bgoug2013 35/56 . Unzip 4. Access via web browser .bat) 6. Needs Java to run 2.io/dbfit 3.github. Copy Oracle JDBC driver (ojdbc6.

Connecting to the database Inline configuration: ! | C o n n e c t | l o c a l h o s t : 1 5 2 1 | u s e r n a m e | p a s s w o r d | d b n a m e | Using properties file: ! | C o n n e c t U s i n g F i l e | D B C o n n e c t i o n . p r o p e r t i e s | s e r v i c e = l o c a l h o s t : 1 5 2 1 u s e r n a m e = u s e r n a m e p a s s w o r d = p a s s w o r d d a t a b a s e = d b n a m e #bgoug2013 36/56 .

Query ! | i n s e r t | t e s t t b l | | n | n a m e | | 1 | N A M E 1 | | 3 | N A M E 3 | | 2 | N A M E 2 | ! | q u e r y | s e l e c t*f r o mt e s t t b l | | n | n a m e | | 1 | N A M E 1 | | 3 | N A M E 3 | | 2 | N A M E 2 | #bgoug2013 37/56 .

Ordered Query ! | O r d e r e dQ u e r y | s e l e c t*f r o mt e s t t b lo r d e rb yn | | n | n a m e ? | | 1 | N A M E 1 | | 3 | N A M E 3 | | 2 | N A M E 2 | #bgoug2013 38/56 .

Insert ! | i n s e r t | t e s t t b l | | n | n a m e | | 1 | N A M E 1 | | 3 | N A M E 3 | | 2 | N A M E 2 | #bgoug2013 39/56 .

Execute Procedure ! 2N op a r a m e t e r s ! | E x e c u t eP r o c e d u r e | d o _ s t u f f | ! 2F u n c t i o n s-r e t u r nv a l u e sw i t h" ? " ! | E x e c u t eP r o c e d u r e | z l p a d _ n o t r u n c | | p _ s t r | p _ p a d d e d _ l e n | ? | | ' 1 2 ' | 5 | ' 0 0 0 1 2 '| ! 2O U Tp a r a m e t e r s-" ? "s u f f i x ! | E x e c u t eP r o c e d u r e | s p l i t _ n a m e | | p _ f u l l n a m e| p _ f i r s t _ n a m e ? | p _ l a s t _ n a m e ? | | M i k e yM o u s e | M i c k e y | M o u s e | ! 2I NO U Tp a r a m e t e r s-s p e c i f yt w i c e ! | E x e c u t eP r o c e d u r e | m a k e _ d o u b l e | | x | x ? | | 3 | 6| #bgoug2013 40/56 .

Expect exception ! 2E x p e c tO R A 2 0 0 1 3 ! | E x e c u t ep r o c e d u r ee x p e c te x c e p t i o n | s e t _ a g e | 2 0 0 1 3 | | p _ a g e | | 5 | #bgoug2013 41/56 .

Parameters and fixture symbols s e tp a r a m e t e rto set parameter directly > > p a r a m n a m e.read the value ! | s e tp a r a m e t e r | O N E | 1 | ! | q u e r y | s e l e c ts y s d a t em y t i m ef r o md u a l | | m y t i m e ? | | > > c u r r e n t _ t i m e | ! | q u e r y | s e l e c tc o u n t ( * )c n tf r o md u a lw h e r es y s d a t e> =: c u r r e n t _ t i m e | | c n t | | < < O N E | #bgoug2013 42/56 .store a value < < p a r a m n a m e.

Store Query ! | S t o r eQ u e r y | s e l e c t1nf r o md u a lu n i o ns e l e c t2nf r o md u a l | f i r s t t a b l e | ! | q u e r y | < < f i r s t t a b l e | | n | | 1 | | 2 | #bgoug2013 43/56 .

Compare Stored Queries ! | i n s e r t | t e s t t b l | | n | n a m e | | 1 | N A M E 1 | | 3 | N A M E 3 | | 2 | N A M E 2 | | S t o r eQ u e r y | s e l e c t*f r o mt e s t t b l | f r o m t a b l e | | S t o r eQ u e r y | ! -s e l e c t1n .' n a m e 1 'n a m ef r o md u a l | f r o m d u a l | | c o m p a r es t o r e dq u e r i e s | f r o m t a b l e | f r o m d u a l | | n a m e | n ? | Use ? suffix for non-key columns #bgoug2013 44/56 .

Working Modes of fixtures Flow Standalone #bgoug2013 45/56 .

Working Modes of fixtures (2) Flow mode A DatabaseTest fixture controls the whole page and coordinates testing OracleTest. DerbyTest.. Automatic rollback at the end (manual commit or rollback is still possible) Better isolation Some additional features such as inspections of stored procedure error results #bgoug2013 46/56 . DB2Test. MysqlTest.. .

Working Modes of fixtures (3) Standalone mode We are responsible for transaction management Enables more control over the database testing process Allows using other individual fixtures We can supply our own database connection to make sure that (Java) integration tests are running in the same transaction #bgoug2013 47/56 .

f i x t u r e | ! | D a t a b a s e E n v i r o n m e n t | o r a c l e | | c o n n e c t | l o c a l h o s t : 1 5 2 1 | d b u s e r n a m e | d b p a s s w o r d | m y d b | #bgoug2013 48/56 . . . ) ) | ! 3I nS t a n d a l o n em o d e | i m p o r tf i x t u r e | | d b f i t . O r a c l e T e s t | ! | C o n n e c t | o u r h o s t : 1 5 2 1 | d b u s e r n a m e | d b p a s s w o r d | m y d b | #A l t e r n a t i v e l y-T N Sd e s c r i p t o rc a nb eu s e d : # ! | C o n n e c t | ( D E S C R I P T I O N = ( A D D R E S S = .Connecting to databse ! 3I nF l o wm o d e ! | d b f i t .

s h | ! | Q u e r y | s e l e c t*f r o me m p l o y e e | | i d | n a m e ?| d e p t ? | s a l a r y ? | | 1 0 0 | T h o m a s | S a l e s | 5 0 0 0 | | 2 0 0 | J a s o n| T e c h n o l o g y | 5 5 0 0 | | 3 0 0 | M a y l a| T e c h n o l o g y | 7 0 0 0 | | 4 0 0 | N i s h a| M a r k e t i n g| 9 5 0 0 | | 5 0 0 | R a n d y| T e c h n o l o g y | 6 0 0 0 | | 5 0 1 | R i t u | A c c o u n t i n g | 5 4 0 0 | #bgoug2013 49/56 . C o m m a n d L i n e F i x t u r e | | c o m m a n d | $ { P R O J E C T _ R O O T } / l o a d e r d e m o / l o a d _ e m p l o y e e . o b j e c t m e n t o r . f i x t u r e s .Integration test with SQL*Loader Compile CommandLineFixture (by Bob Martin) Use it to run a shell script ! 3L o a ds o m ed a t aw i t hO r a c l eS Q L * L o a d e r | c o m .

org/FitNesse.RestfulServices JUnit #bgoug2013 50/56 .Automating tests execution Running tests from command line j a v aj a rf i t n e s s e s t a n d a l o n e .UserGuide. j a r\ d" $ { T E S T S _ D I R } "\ c" B g o u g D e m o S u i t e ? s u i t e & f o r m a t = t e x t " Run test or suite as RESTful service http://fitnesse.

xml .metadata (Test. Sute) Easy to put under version control #bgoug2013 51/56 .test definition and other Wiki content properties.How tests are stored? Simple text files content.txt .

Demo #bgoug2013 52/56 .

Summary Changes of database code and schema are often relatively hard This makes the systems considered legacy TDD stimulates designing cleaner and easier to change code Development of RDBMS artefacts is lagging when it comes to engineering practices and tools DbFit can help #bgoug2013 53/56 .

github. suggestions and contributions are welcome https://github. Scott W.with links to: download DbFit docs. Sadalage #bgoug2013 54/56 . Ambler.don't hesitate to participate and ask questions code repository at github . http://www.net/2007/11/20/fighting-the-monster http://www.org/essays/tdd.reports for problems. Pramodkumar J. getting started information mailing list .io/dbfit .agiledata.agiledata.com/javornikolov/tdd-with-dbfit-bgoug-201305 http://gojko.org Test Driven Development: By Example.html.Resources http://benilovj.Evolutionary Database Design. Kent Beck Refactoring Databases .

Thank You! nikolov dot javor at gmail .

Q&A #bgoug2013 56/56 .