Testing orm based code
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Testing orm based code

on

  • 927 views

It is always a pain to test code with DB/ORM-dependencies. So, here the rules to ease the process ...

It is always a pain to test code with DB/ORM-dependencies. So, here the rules to ease the process ...

Statistics

Views

Total Views
927
Views on SlideShare
883
Embed Views
44

Actions

Likes
0
Downloads
0
Comments
0

3 Embeds 44

http://localhost 29
http://webbylab.com 13
http://koorchik.blogspot.com 2

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Testing orm based code Presentation Transcript

  • 1. Testing ORM base codeViktor TurskyiCTO at WebbyLabKiev 2012
  • 2. Bad NewsORM-based code is databasedependent codeORM framework is a blackbox
  • 3. Good newsORM is about objects and classesWe can do testing without objectpersistency
  • 4. Rule 1: No tests for simple classespackage Language;use base qw(Rose::DB::Object);__PACKAGE__->meta->setup( table => languages, columns => [ language_id => { type => varchar, length => 3, not_null => 1 }, name => { type => varchar, length => 64, not_null => 1 }, ], primary_key_columns => [ language_id ],);We do not test ORM framework - it has owntests.
  • 5. Rule 2: Try inject dependenciespackage VAT;use base qw(Rose::DB::Object);__PACKAGE__->meta->setup( table => vats, columns => [ vat_id => { type => varchar, length => 16, not_null => 1 }, rate => { type => integer, not_null => 1 }, ], primary_key_columns => [vat_id],);sub netto2vat { ... }sub brutto2vat { ... }
  • 6. Real life VS tests# In real lifemy $vat = VAT->new(vat_id => VAT_20)->load();my $vat_amount = $vat->netto2vat(102.51);...# In testsmy $vat_obj =VAT->new( rate => 20 );is( $vat_obj->brutto2vat(123.01), 20.50, Checking brutto2vat calculations );is( $vat_obj->brutto2vat(456.00), 76.00, Checking brutto2vat calculations );is( $vat_obj->netto2vat(102.51), 20.50, Checking netto2vat calculations );is( $vat_obj->netto2vat(380.00), 76.00, Checking netto2vat calculations );
  • 7. Real life VS tests (complex)# In real lifemy $fin_event = FinEvent->new( amount => 102.22, # vat_object => ???)->load();my $amount = $fin_event->calculate_vat_amount();# In testsmy $fin_event = FinEvent->new( vat_object => VAT->new( rate=>20 ), amount => 102.22);is( $fin_event->calculate_vat_amount(), 20.44, VAT calculation );
  • 8. But still a lot of logic requires DBSo, bad news again:In complex operation injection is not alwayssuitable due to complex dependenciesUsing of DBI mock objects is not a good waydue to blackbox nature of the ORM frameworkOne Data Base for whole Model
  • 9. Simple solutionJust to use the same predefined set of data forall testcountries, users, companies, banks, materials, products, customers, partners,vats, stocks, languages, currencies,currency rates, units... and a lot moreShared set of predefined data worked until westarted work on aggregated reports. Everyreport require a new set of test data whichbreaks other tests data.
  • 10. Rule 3: Individual test environmentfor each tests setRecreate database for each tests set?=> It takes too much time :(Use embedded DB like SQLite (you can copy file)?=> It requires support of two database schemas :(Manually delete data after each test?=> It requires additional cleanup procedures :(
  • 11. What we do?Just revert transaction after test :)use Test::More;my $db = Rose::DB->new_or_cached();$db->begin_work();prepare_test_data();do_testing();$db->rollback();
  • 12. ConclusionsRule 1: No tests for simple classesRule 2: Try inject dependenciesRule 3: Individual test environment for each test
  • 13. Take a look at our testsmy $t = Test::Project->new(); # starts new transaction$t->standard_setup() ->add_material_from_partner( 1200 ) ->add_service_from_partner( 600, {date=>2011-10-11} ) ->add_material_sale(60, {currency_rate=>800, currency_id=>USD});iterate_test_data( report_a, sub { my $data = shift; my $report = Report::A->new(%{ $data->{input} }); $t->test_correct_report($report, $data);});# on $t->DESTROY() - will revert transaction
  • 14. Viktor Turskyiviktor@webbylab.com http://koorchik.blogspot.com http://search.cpan.org/~koorchik/ https://github.com/koorchik WebbyLab http://webbylab.com