tddwithdbfitandoracle-bgougconference2013-05-18-130520132024-phpapp01

Embed Size (px)

Citation preview

  • TDD with DbFit and OracleWriting readable, easy to maintain unit and integration tests fordatabase code

    Yavor Nikolov

    BGOUG Conference, 2013-05-18

  • Agenda

    #bgoug2013

    Concepts (Testing, Test-Driven Development)DbFitDemo

    2/56

  • What is a legacy system?

    #bgoug2013

    You spot an obvious design problemknow how to improve that,but the thought about consequences gives you astomach ache.

    source: Gojko Adzic, "Fighting the monster"

    3/56

  • #bgoug2013

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

    4/56

  • Why (automated) testing?

    #bgoug2013

    Makes application change easierSafety net - provides confidence/removes fearDocumentationHelp to localize where exactly a defect is locatedReduce the chance of new bugsAutomation enables earlier feedback, saves time,helps focusing on solving the main problem. (Noteverything is feasible to automate)

    5/56

  • Test Fixture

    #bgoug2013

    All the things we need to have in place in order torun a test and expect a particular outcomeThe test context

    6/56

  • System Under Test (SUT)The system that is being tested

    #bgoug2013 7/56

  • Test execution cycle

    #bgoug2013

    Arrange (set up the Fixture)Act (exercise the System Under Test)Assert (verify results are as expected)Tear Down the fixture (to isolate other tests fromthis one)

    1.2.3.4.

    8/56

  • Unit test

    #bgoug2013

    Tests small individual unit (module,procedure/function)In isolation (no interaction with other units)Should run quickly (otherwise people won't runthem)

    9/56

  • Integration test

    #bgoug2013

    Tests several modules as a groupSlower than unit tests (usually)

    10/56

  • Acceptance test

    #bgoug2013

    Conducted to determine whether or not a systemsatisfies its acceptance criteriaand to enable the customer to determine whether ornot to accept the system.At least modeled and possibly even written by thecustomerEnd-to-end (slower than Integration & Unit tests)

    11/56

  • Regression tests(Regress vs progress)

    Performed to make sure that previously workingfunctionality still works after changes elsewhere inthe system

    #bgoug2013 12/56

  • RefactorIs the the process of changing a system in such a waythat

    Doing refactoring without tests is unsafe

    #bgoug2013

    doesn't alter external behaviourand improves it's internal structure (design)through small steps

    13/56

  • TDD Cycle

    #bgoug2013

    source: Internet

    14/56

  • Tests are not the main product in TDD

    #bgoug2013

    TDD is a design techniqueThe design emerges in small steps

    15/56

  • Why test first?

    #bgoug2013

    Start with end in mind (think from point of view ofcaller)This perspective helps for better designTest coverage is useful byproductGreatly reduces the need of debugging

    16/56

  • Cost of change (traditional)

    #bgoug2013 17/56

  • Cost of change (test early)

    #bgoug2013 18/56

  • Why testing the Database?

    #bgoug2013

    For lot of businesses, data held in DB are the mostvital commercial asset they haveBusiness critical functions rely on this dataSo it makes sense to validate that data is stored andprocessed correctly

    19/56

  • Challenges of Database testing...

    #bgoug2013

    Bad tools

    Inherently hard to test. Isolation is difficult

    Attitude ("it's not my job")

    Too much boilerplate codeOO tools not directly applicable for RDBMS

    Changes are persistentShared environmentTriggers, Constraints

    20/56

  • How to isolate db tests?Run tests in one transaction

    #bgoug2013

    Makes them repeatable and independentWhen one transaction is not an option - clean upafter tests

    21/56

  • How to isolate db tests (2)?Dedicated database

    #bgoug2013

    One db per contributorSeparate schemasShared Dev db may work tooAs a rule - avoid running tests on top of production

    22/56

  • Other Tips

    #bgoug2013

    Make tests self-sufficientDon't count on the order of testsPrepare everything you need for the test in its set-up

    23/56

  • #bgoug2013

    DbFit

    24/56

  • What is DbFit?

    #bgoug2013

    Initially created by Gojko Adzic:

    Enables manipulating database objects and definingtests in tabular formOpen source https://github.com/benilovj/dbfit

    to enable efficient database testingmotivate database developers to use anautomated testing framework

    25/56

  • DbFit, FIT and FitNesse

    #bgoug2013

    DbFit is based on FIT+FitNesse+DB Fixtures whichenable FIT/Fitnesse tests to execute directly against adatabase.FIT is Acceptance testing framework

    FitNesse is Wiki-web based front-end for FIT

    customer orientedtests are described as tables

    26/56

  • FitNesse architecture

    #bgoug2013

    source: Fittnesse User Guilde - One Minute Description

    27/56

  • What is DbFit Fixture?

    #bgoug2013

    A fixture is interface between:

    In general there is 1:1 mapping between Fit tableand fixture

    the test instrumentation (Fit framework),test cases (Fit tables),and the system under test (e.g. a databasestored procedure)

    28/56

  • Why DbFit?

    #bgoug2013

    Easy to use (even for non-technical people)

    Provides all the plumbing:

    Runs inside FitNesse - already integrated with lots ofother tools/libraries

    Tests expressed and managed as tablesWeb-Wiki front-end

    Transaction managementFeatures based on meta-dataParameter mapping

    29/56

  • What is Wiki?

    #bgoug2013

    The simplest online database that could possiblywork. - Ward CunninghamAllows users to freely create and edit Web pagecontent using any Web browserA group communication mechanismsEncourages democratic use of the Web andpromotes content composition by nontechnicalusers

    source: http://wiki.org/wiki.cgi?WhatIsWiki

    30/56

  • Fitnesse Wiki

    #bgoug2013

    Hierarchies - SubWiki, Test SuitesPage types - Suite, Test, StaticSome special pages:

    http://fitnesse.org/FitNesse.UserGuide

    PageHeader, PageFooterSetUp, TearDown, SuiteSetUp, SuiteTearDownInherited recurively by default; can be overriden

    31/56

  • A Unit test with DbFit

    #bgoug2013

    Set up the input data (arrange).Execute a function or procedure (act).Run a query and compare actual vs expected data(assert).

    1.2.3.

    32/56

  • Basic commands of DbFit

    #bgoug2013

    QueryInsertUpdateExecute ProcedureExecute

    33/56

  • Advanced features

    #bgoug2013

    Inspect queries, tables, procedures to auto-generatetest tables and regression testsStore and compare queriesStandalone mode for full control

    34/56

  • Getting started

    #bgoug2013

    Needs Java to runDownload: http://benilovj.github.io/dbfitUnzipCopy Oracle JDBC driver (ojdbc6.jar) to lib subfolderRun the startup script (startFitnesse.sh orstartFitnesse.bat)Access via web browser - http://localhost:8085

    1.2.3.4.5.

    6.

    35/56

  • Connecting to the databaseInline configuration:

    Using properties file:

    #bgoug2013

    !|Connect|localhost:1521|username|password|dbname|

    !|ConnectUsingFile|DBConnection.properties|

    service=localhost:1521username=usernamepassword=passworddatabase=dbname

    36/56

  • Query

    #bgoug2013

    !|insert|testtbl||n |name ||1 |NAME1 ||3 |NAME3 ||2 |NAME2 |

    !|query|select * from testtbl||n |name ||1 |NAME1 ||3 |NAME3 ||2 |NAME2 |

    37/56

  • Ordered Query

    #bgoug2013

    !|Ordered Query|select * from testtbl order by n||n |name? ||1 |NAME1 ||3 |NAME3 ||2 |NAME2 |

    38/56

  • Insert

    #bgoug2013

    !|insert|testtbl||n |name ||1 |NAME1 ||3 |NAME3 ||2 |NAME2 |

    39/56

  • Execute Procedure

    #bgoug2013

    !2 No parameters!|Execute Procedure|do_stuff|

    !2 Functions - return values with "?"!|Execute Procedure|zlpad_notrunc ||p_str |p_padded_len|? ||'12' |5 |'00012' |

    !2 OUT parameters - "?" suffix!|Execute Procedure|split_name||p_fullname |p_first_name?|p_last_name?||Mikey Mouse|Mickey |Mouse |

    !2 IN OUT parameters - specify twice!|Execute Procedure|make_double||x|x?||3|6 |

    40/56

  • Expect exception

    #bgoug2013

    !2 Expect ORA-20013!|Execute procedure expect exception|set_age|20013||p_age ||-5 |

    41/56

  • Parameters and fixture symbols

    #bgoug2013

    set parameter to set parameter directly>>paramname - store a valuecurrent_time |

    !|query|select count(*) cnt from dual where sysdate >= :current_time||cnt ||

  • Store Query

    #bgoug2013

    !|Store Query|select 1 n from dual union select 2 n from dual|firsttable|

    !|query|

  • Compare Stored Queries

    #bgoug2013

    !|insert|testtbl||n |name ||1 |NAME1 ||3 |NAME3 ||2 |NAME2 |

    |Store Query|select * from testtbl|fromtable|

    |Store Query|!- select 1 n, 'name1' name from dual|fromdual|

    |compare stored queries|fromtable|fromdual||name |n? |

    Use ? suffix for non-key columns

    44/56

  • Working Modes of fixtures

    #bgoug2013

    FlowStandalone

    45/56

  • Working Modes of fixtures (2)Flow mode

    #bgoug2013

    A DatabaseTest fixture controls the whole page andcoordinates testing

    Automatic rollback at the end (manual commit orrollback is still possible)Better isolationSome additional features such as inspections ofstored procedure error results

    OracleTest, MysqlTest, DerbyTest, DB2Test, ...

    46/56

  • Working Modes of fixtures (3)Standalone mode

    #bgoug2013

    We are responsible for transaction managementEnables more control over the database testingprocessAllows using other individual fixturesWe can supply our own database connection tomake sure that (Java) integration tests are running inthe same transaction

    47/56

  • Connecting to databse

    #bgoug2013

    !3 In Flow mode!|dbfit.OracleTest|!|Connect|ourhost:1521|dbusername|dbpassword|mydb|

    # Alternatively - TNS descriptor can be used:#!|Connect|(DESCRIPTION=(ADDRESS=...))|

    !3 In Standalone mode|import fixture||dbfit.fixture|!|DatabaseEnvironment|oracle||connect|localhost:1521|dbusername|dbpassword|mydb|

    48/56

  • Integration test with SQL*Loader

    #bgoug2013

    Compile CommandLineFixture (by Bob Martin)Use it to run a shell script

    !3 Load some data with Oracle SQL*Loader|com.objectmentor.fixtures.CommandLineFixture ||command|${PROJECT_ROOT}/loaderdemo/load_employee.sh|

    !|Query|select * from employee ||id |name? |dept? |salary?||100 |Thomas|Sales |5000 ||200 |Jason |Technology|5500 ||300 |Mayla |Technology|7000 ||400 |Nisha |Marketing |9500 ||500 |Randy |Technology|6000 ||501 |Ritu |Accounting|5400 |

    49/56

  • Automating tests execution

    #bgoug2013

    Running tests from command line

    Run test or suite as RESTful servicehttp://fitnesse.org/FitNesse.UserGuide.RestfulServices

    JUnit

    java -jar fitnesse-standalone.jar \ -d "${TESTS_DIR}" \ -c "BgougDemoSuite?suite&format=text"

    50/56

  • How tests are stored?

    #bgoug2013

    Simple text filescontent.txt - test definition and other Wiki contentproperties.xml - metadata (Test, Sute)Easy to put under version control

    51/56

  • #bgoug2013

    Demo

    52/56

  • Summary

    #bgoug2013

    Changes of database code and schema are oftenrelatively hardThis makes the systems considered legacyTDD stimulates designing cleaner and easier tochange codeDevelopment of RDBMS artefacts is lagging when itcomes to engineering practices and toolsDbFit can help

    53/56

  • Resources

    #bgoug2013

    http://benilovj.github.io/dbfit - with links to:

    https://github.com/javornikolov/tdd-with-dbfit-bgoug-201305http://gojko.net/2007/11/20/fighting-the-monsterhttp://www.agiledata.org/essays/tdd.html, http://www.agiledata.orgTest Driven Development: By Example, Kent BeckRefactoring Databases - Evolutionary Database Design, Scott W. Ambler, Pramodkumar J. Sadalage

    download DbFitdocs, getting started informationmailing list - don't hesitate to participate and ask questionscode repository at github - reports for problems, suggestions and contributions are welcome

    54/56

  • Thank You!nikolov dot javor at gmail

  • Q&A#bgoug2013 56/56