Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test...

64
Test - Driven Development in the Database How I Do It [email protected] @NiceTheoryVidar Vidar Eidissen

Transcript of Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test...

Page 1: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Test-Driven Development in the Database

– How I Do It

[email protected] @NiceTheoryVidar

Vidar Eidissen

Page 2: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Short bio• Oracle Database Consultant / Developer / (DBA)

• Oracle databases since 1998

• 23 years @ the biggest EHR-vendor in Norway;DIPS ASA - 80.000+ users in 3 of 4 health regions

• Consulting since 2016

• ETL, performance, db development

• Application performance troubleshooting

• #SmartDB/#PinkDB-afficionado

Page 3: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...
Page 4: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

June 20th @ 23:30

Page 5: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...
Page 6: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...
Page 7: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Karsten Wallin Kjetil Strønen Vidar Eidissen Lasse Jenssen ♠

Page 8: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Why am I here?

• I've wanted to see a presentation on this subject for several years

• Nobody did it

• So: Here I am…

Page 9: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Presentation content

Tools and frameworks

Coding techniques

some

most – independent of tools

Continuous Integration nothingContainers

Page 10: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Context for this presentation

Page 11: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Business Logic

External API

Low level API

Business Logic

External API

Low level API

Business Logic

External API

Low level API

Business Logic

External API

Low level API

Business Logic

External API

Low level API

Database code

Table Table Table Table Table

Front end servers

Clients

SmartDB

Page 12: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Writing code the regular way• Design

• Write code

• Inspect

• Do some manual testing

• Fix bugs

• Test some more

• But you only test the one thing that you changed…

Page 13: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Agile

Embrace change!

Page 14: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Writing code the regular way• Design

• Write code

• Inspect

• Do some manual testing

• Fix bugs

• Test some more

• But you only test the one thing that you changed…

Page 15: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

The process needs improvement

Page 16: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Test Driven Design

• TDD definition:

• Requirements are turned into very specific test cases

• TDD encourages simple designs and inspires confidence - Kent Beck

Source: Wikipedia

Page 17: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

The TDD process1. Add a test

2. Run all tests and see if the new test fails

3. Write the code (quickly to solve the case)

4. Run tests

5. Refactor code

6. Repeat Source: Wikipedia

Page 18: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Hence…

Page 19: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

You should not write new code before you have a failing test

Page 20: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

However…

I always write my procedure interface first

Why?

Because I can then use autocomplete in my IDE when I write the test

Page 21: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

But I always write a failing test and run it

This ensures that the test actually fails and is being run

This acts as a canary bird so I don’t forget to declare the test in the package header

Page 22: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Naming of tests• <what_procedure/function>_<with_what_input>_<expected_result>

• I don't name them as test_<something>

• That it is a test is given from the context

• I can immediately see what the test is about and what has failed

• Naming like this is a challenge on 11g and below

• The possibilities for long identifiers in 12c and above is a bliss

Page 23: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Think of test names as

a requirement of your system

Page 24: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Note to self: Show basic example

Page 25: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

I’m not totally useless…

– I can be used as a bad example

Page 26: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Examples; test-names

provision_access_for_reservation_with_valid_reservation_inserts_access_records

provision_access_for_reservation_with_valid_reservation_sets_correct_access_times

approve_membership_without_privileges_raises_exception

approve_membership_as_org_admin_approves_membership

approve_membership_as_approver_approves_membership

request_membership_with_auto_approvable_mail_domain_auto_approves_request

Page 27: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

--%test procedure reserve_for_booking_with_null_user_given_books_for_current_user;

--%test procedure reserve_for_booking_with_payable_resource_creates_order_with_credit_card_payment;

--%test --%throws(-20000) procedure booking_with_cc_payment_and_no_payment_reference_raises_exception;

--%test procedure booking_with_cc_payment_and_confirmation_with_payment_reference_confirms_booking;

--%test procedure confirm_booking_with_cc_order_removes_open_payment_request;

--%test procedure confirm_payment_with_cc_order_creates_invoice;

--%test procedure confirm_payment_with_cc_order_removes_open_payment_request;

--%test procedure cancel_order_for_membership_cancels_membership_request;

--%test procedure cancel_order_for_booking_cancels_pending_booking;

Page 28: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Sometimes I break the patternreject_membership_rejects_membership

approve_membership_creates_correct_vouchers

I’m not saying it’s correct to break the pattern like this.

– I’m just observing my own code.

These could/should have been named otherwise.

Page 29: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Test-examples

Page 30: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

procedure reserve_for_booking_with_no_payment_sets_booking_status_to_tentative is l_reservation_id number; l_start timestamp with time zone; l_end timestamp with time zone; l_reservation p_reservation.reservation_t; begin l_start := next_monday_at('09:00'); l_end := l_start + interval '30' minute; set_slot_attributes_for_resource(resource_id_in => c_minute_based_resource, price_in => 0, slot_size_in => 15); l_reservation_id := p_booking.reserve_for_booking(resource_id_in => c_minute_based_resource, service_id_in => null, user_id_in => p_user_session.user_id, from_time_in => l_start, to_time_in => l_end); l_reservation := p_reservation.reservation(l_reservation_id); ut.expect(l_reservation.net_price).to_(equal(0)); ut.expect(l_reservation.gross_price).to_(equal(0)); ut.expect(l_reservation.status).to_(equal(p_booking.c_status_reserved)); end;

next_monday_at(’09:30') would have given better readability

I try to use my APIs instead of writing SQL statements in tests. Improves

maintainability

Page 31: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

function next_monday_at(hh24mi_in in varchar2) return timestamp with time zone is l_tz timestamp with time zone; begin l_tz := to_timestamp_tz(to_char(trunc(sysdate + 7, 'iw'), 'yyyy-mm-dd') || ' ' || hh24mi_in || ':00 +02:00', 'yyyy-mm-dd hh24:mi:ss tzh:tzm'); return l_tz; end;

Redundant. Could have done just return …

Does not account for daylight savings time

Page 32: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

– Roy Osherove

« Your test should test one thing and one thing only »

Page 33: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Define "one thing"

• It’s usually not a single attribute

• It’s about the state after completing an execution of the code you’re testing

Page 34: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Test data for unit-testing• My goal is to prove correctness of my code

• I don't use production data

• I don't need to use a production size database either

• Performance testing is a different thing

• The important thing is to know my data

• I just need to have sufficient data to run the test-cases

Page 35: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Tools

• Different IDEs have different support for test-building

• I prefer not to use these for several reasons

• Binds you to the IDE

• Can be difficult to set up automated testing

• Often incurs a bit of mouse clicking

Page 36: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

utPLSQL v3• http://utplsql.org

• https://github.com/utPLSQL/utPLSQL

• Originally written by Steven Feuerstein

• Rewritten by Jacek Gebal and several others

• Very easy to get started

• Good integration with CI-tools

Page 37: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

When my code doesn't work as expected

• If the test-result (failed assert) doesn’t convey what’s wrong, I go to my logs

• If I don’t get an understanding of the problem, I improve my logs

• Stepping through the code is my last resort (and gives me a sense of failure)

• In production, logs document what happened.

• Getting access to production to step through code might not be that easy. Or appropriate.

• Fixing errors based on TDD can improve your logging/instrumentation skills

Page 38: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Coding style

Page 39: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Commits

Page 40: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Business Logic

External API

Low level API

Business Logic

External API

Low level API

Business Logic

External API

Low level API

Business Logic

External API

Low level API

Business Logic

External API

Low level API

Database code

Table Table Table Table Table

Front end servers

Clients

SmartDB

Page 41: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Readability

( Clean code )

Page 42: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Encapsulation

Page 43: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Exception handling

Page 44: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Use helper functions– For readability

– For shorter code (DRY)

Page 45: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Maintaining test-code• Test code has to be maintained just like regular code

• Not writing or maintaining them creates a debt that will have to be paid off later when I wish I had them

• Therefore, I try to keep my test-cases short, simple and understandable

• When I write code to check my result, I try to not write new code

• Use my own API’s as far as possible instead of writing new selects

• Delete obsolete tests

Page 46: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Stay calm

• I don’t test everything

• I don’t keep track of code coverage

• Although it might be useful i larger teams

• I don’t loose sleep over missing tests

• I’m more disturbed by badly tested code

Page 47: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Staying on top

• When a bug is reported, I try to write a test replicating the bug

• For less well defined bugs, this may be difficult - so I troubleshoot first

• Retrofitting tests on old code is time consuming and feels counter-productive

Page 48: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

TDD doesn’t find all errors

• Had a bug where a search service returned invalid results

• No unit-tests were able to unveil the problem

• Turned out the client used different inputs for the two service calls

Page 49: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Remember

Page 50: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Your tests are an excellent tool for you and your successors to manage

and change your legacy code

Page 51: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...
Page 52: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

MentalitySpeed

ToolsPerformance

Page 53: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Performance?

Page 54: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

TDD encourages simple designs and inspires confidence

Page 55: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

I like encapsulation

• I like to build top-down, then bottom-up and work in waves like that

• I try to keep my interfaces "narrow" - not exposing my inner needs

• If it’s "correct"?

• I don’t know

• But that’s often how I work out additional requirements (context) in the input

Page 56: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

As a result

• I have a tendency to create methods taking id’s as inputs

• This often makes the units easy to test (less code)

• It can have a performance downside - but is it important?

• Since I instrument my client calls with method and action, I can easily determine if the methods need a performance review when traffic picks up

Page 57: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

procedure book_hour_based_resource_with_valid_resource_and_time_creates_booking is l_booking p_booking.booking_t; l_booking_id number; l_start_time timestamp with time zone := next_monday_at('14:00'); l_end_time timestamp with time zone := next_monday_at('16:00'); l_adjusted_end_time timestamp with time zone; begin l_booking_id := p_booking.reserve_for_booking(resource_id_in => c_hour_based_resource, service_id_in => null, user_id_in => p_user_session.user_id, from_time_in => l_start_time, to_time_in => l_end_time); l_booking := p_booking.get(booking_id_in => l_booking_id); ut.expect(l_booking.resource_id).to_(equal(c_hour_based_resource)); ut.expect(l_booking.service_id).to_(be_null); ut.expect(l_booking.start_time).to_(equal(l_start_time)); ut.expect(l_booking.end_time).to_(equal(l_end_time)); end;

Rename to"booking"?

Could have returned a booking_t-type

A PL/SQL record type

Page 58: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

A better example l_invoice_org_id := get_invoice_org_id(user_id_in => l_user_id, resource_in => l_resource_id); l_display_end_time := calculate_end_time(l_resource_id, to_time_in);

resource_is_bookable_in_given_time(l_resource_id, l_user_id, from_time_in, to_time_in); l_initial_price := resource_net_price(l_resource_id, l_user_id, from_time_in, to_time_in);

Yes – of course! These functions and procedures where looking up the

resource in their internal implementation

Page 59: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

An easy fix l_resource p_resource.resource_t;begin

l_resource := p_resource.resource(resource_id_in => resource_id_in); l_invoice_org_id := get_invoice_org_id(user_id_in => l_user_id, resource_in => l_resource); l_display_end_time := calculate_end_time(l_resource, to_time_in); resource_is_bookable_in_given_time(l_resource, l_user_id, from_time_in, to_time_in); l_initial_price := resource_net_price(l_resource, l_user_id, from_time_in, to_time_in);

user_id may still be a case

Page 60: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Anyway…

Page 61: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

– Donald Knuth

The real problem is that programmers have spent far too much time

worrying about efficiency in the wrong places and at the wrong times;

premature optimization is the root of all evil

(or at least most of it) in programming.

Page 62: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Watch Kevlin Henney’s presentation on JavaZone 2018:

Structure and Implementation of Test Cases

https://player.vimeo.com/video/289852238

Page 63: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Time for questions?

Page 64: Test Driven Development in the Database How I Do It · – Roy Osherove « Your test should test one thing and one thing only » ...

Thank you for your attention!

Blog: nicetheory.io

Twitter: @NiceTheoryVidar

Email: [email protected]