21 December 2006

Test-Driven Development With Oracle's PL/SQL

Test Güdümlü Programlama(Test-Driven Development), çevik(agile) yöntemlerden biri olan XP(Extreme Programming)'in bir parçasıdır. Son zamanlarda sıklıkla yaşanan, yazılımın istendiği şekilde çalışmaması olarak tanımlanan bug'ların tehlikeli ve maliyetli sonuçları ile kendinden daha bir söz ettiren TDD, kaliteli yazılım ürününün oluşması için çalışır. 2002 yılında ComputerWorld'un yaptığı araştırmaya göre bug'ların analiz ve çözümünün ABD ekonomisine yaklaşık 60 milyar $ maliyeti de düşünülürse, TDD'nin ne derece önemli bir konu olduğu daha iyi farkedilecektir.
Genel olarak test yöntemleri başta ve sonda olmak üzere 2 türlüdür. Testin sonda yapılması klasik yöntemdir. Kod yazılır ve sonunda testler(unit) yapılır. Testi başa almak ise TDD'nin temelini oluşturur. Kod yazılmadan testleri yazılır ve daha sonra kodlamaya girilir. En sonunda ise gerekli durumlarda refactoring olarak iyileştirmeler yapılır.
TDD'yi oluşturan test-first development aşağıdaki döngü ile belirtilebilir:

Kodlama Yapılmaz
Test Yazılır
Test Çalıştırılır
Test Hata Alır
Testi Geçebilecek Kadar Kod Yazılır
Tekrar Çalıştırılır
Hata Alınırsa İşlemler Tekrarlanır
Test Hatasız Geçilir
Test Yazılır
…...

TDD'nin sağladığı avantajlar ise şu şekilde belirtilebilir:

Yüksek Kalitede Kod(Yazılım Ürünü) Oluşur.
Yazılımın Doğru Çalıştığının Kanıtıdır.
Büyük Problemleri Küçük Parçalara Böler.
Her Test Döngü Sonucu Geribildirimlere İmkan Tanır.
Evrimsel Yazılım Geliştirme Yöntemlerini Destekler.

Java için JUnit, .NET için NUnit ve PL/SQL için ise OUnit TDD ile kullanılabilecek araçlara örnek verilebilir.

PL/SQL ile bu yöntemi kullanarak yazılan örnek bir uygulama aşağıda belirtilmiştir. Bu örnek, kendisine parametre olarak gelen bir tarihi, istenen formata dönüştürme işlemini gerçekleştirmektedir.

Format için gerekli tablo oluşturulur:
SQL> create table date_formats( id number, format varchar2(16));
Table created
SQL> insert into date_formats values(1, 'MMDDYY');
1 row inserted
SQL> insert into date_formats values(2, 'MM.DD.YYYY');
1 row inserted
SQL> select * from date_formats;
        ID FORMAT
---------- ----------------
         1 MMDDYY
         2 MM.DD.YYYY

SQL>

Test Yazılır:
SQL> create or replace package date_format_tests as
  2    procedure test_format1;
  3  end;
  4  /

Package created
SQL> show err;
No errors for PACKAGE HR.DATE_FORMAT_TESTS

SQL> create or replace package body date_format_tests as
  2 
  3    procedure test_format1 is
  4      vn_FormatId number;
  5      vs_FormattedDate varchar2(32);
  6      vs_Expected varchar2(32);
  7      vd_Date date;
  8    begin
  9      vn_FormatId := 1;
 10      vd_Date := to_date('01.12.2006', 'MM.DD.YYYY');
 11      vs_Expected := '011206';
 12      vs_FormattedDate := date_format.get_formatted_date(vn_FormatId, vd_Date);
 13      if vs_Expected = vs_FormattedDate then
 14        dbms_output.put_line('Test is Succesful....');
 15      else
 16        dbms_output.put_line('Test Failed!!!');
 17      end if;
 18    end;
 19 
 20  end;
 21  /


Test Hata Alır:
Warning: Package body created with compilation errors
SQL> show err;
Errors for PACKAGE BODY HR.DATE_FORMAT_TESTS:

LINE/COL ERROR
-------- -----------------------------------------------------------------------
12/25    PLS-00201: identifier 'DATE_FORMAT.GET_FORMATTED_DATE' must be declared
12/5     PL/SQL: Statement ignored

SQL> exec date_format_tests.test_format1;
begin date_format_tests.test_format1; end;
ORA-04063: package body "HR.DATE_FORMAT_TESTS" has errors
ORA-06508: PL/SQL: could not find program unit being called: "HR.DATE_FORMAT_TESTS"
ORA-06512: at line 1


Kodlama Yapılır:
SQL> create or replace package date_format as
  2    function get_formatted_date(pin_FormatId in number,pid_Date in date) return varchar2;
  3  end;
  4  /

Package created
SQL> show err;
No errors for PACKAGE HR.DATE_FORMAT

SQL> create or replace package body date_format as
  2 
  3    function get_formatted_date(pin_FormatId in number,pid_Date in date) return varchar2 is
  4    vs_Result varchar2(32);
  5    begin
  6      vs_Result := 'N/A';
  7      return vs_Result;
  8    end;
  9 
 10  end;
 11  /

Package body created
SQL> show err;
No errors for PACKAGE BODY HR.DATE_FORMAT


Test Yanlış Sonuç Üretir:SQL> exec date_format_tests.test_format1;
Test Failed!!!
PL/SQL procedure successfully completed

Tekrar Kodlama Yapılır:
SQL> create or replace package body date_format as
  2 
  3    function get_formatted_date(pin_FormatId in number,pid_Date in date) return varchar2 is
  4    vs_Result varchar2(32);
  5    vs_DateFormat varchar2(32);
  6    begin
  7      select df.format into vs_DateFormat from date_formats df where df.id = pin_FormatId;
  8      vs_Result := to_char(pid_Date,vs_DateFormat );
  9      return vs_Result;
 10    end;
 11 
 12  end;
 13  /

Package body created
SQL> show err;
No errors for PACKAGE BODY HR.DATE_FORMAT



Test Geçer:SQL> exec date_format_tests.test_format1;
Test is Succesful....
PL/SQL procedure successfully completed

İyileştirmeler Yapılır:
SQL> create or replace package body date_format as
  2 
  3    function get_single_query_result(pis_TableName in varchar2,pis_ColumnName  in varchar2, pis_WhereCondition  in varchar2) return varchar2 is
  4      vs_Result varchar2(32);
  5      vs_SqlStatement varchar2(1024);
  6    begin
  7      vs_SqlStatement := 'select ' || pis_ColumnName || ' from ' || pis_TableName ||  '  where ' || nvl(pis_WhereCondition, '1=1');
  8      execute immediate vs_SqlStatement into vs_Result;
  9      return vs_Result;
 10    end;
 11 
 12    function get_formatted_date(pin_FormatId in number,pid_Date in date) return varchar2 is
 13      vs_Result varchar2(32);
 14      vs_DateFormat varchar2(32);
 15    begin
 16      vs_DateFormat := get_single_query_result('date_formats', 'format', 'id = ' || pin_FormatId);
 17      vs_Result := to_char(pid_Date,vs_DateFormat );
 18      return vs_Result;
 19    end;
 20 
 21  end;
 22  /

Package body created
SQL> show err;
No errors for PACKAGE BODY HR.DATE_FORMAT

SQL> exec date_format_tests.test_format1;
Test is Succesful....
PL/SQL procedure successfully completed

No comments: