30 Ekim 2013 Çarşamba

BDD - Cucumber

Projelerin icinde bogustugum donem icinde yazilim dunyasi oyle cok degismis ki simdilerde kendime programci demeye utanir hale geldim. Bildigim herseyi sildim simdi yeniden bir ogrenci edasiyla herseye yeniden baslamanin heyecani ve ogrenecek bir suru konunun bilinci ile meslege yeniden basladim. Zaten bu asamada ya bunu yapacaktim ya da kariyer degistirecektim. Zira bilgisayar programcilarinin kendilerini yenilemediklerinde 5 sene icinde bir hic'e donustugunu cok iyi biliyorum.


Size proje gelistirmede gelinen son noktalardan birisi olan BDD (Behaviour Driven Development) konusunu anlatmaya calisacagim. Bundan birkac hafta oncesine kadar bu konu hakkinda hic bir fikrim yoktu. Hatta hic duymamistim. 

Bildigimiz ogrendigimiz hatta ogrettigimiz, proje gelistirme yontemi su sekilde idi. 
1 - Analiz 
2 - Tasarim ve Planlama 
3 - Gelistirme
4 - Test
5 - Teslim 
6 - Bakim (yani tekrar 1. adimdan baslayan bir dongu) 

Bu yontemde sorun olan nokta Analiz ve Teslim sirasinda musteri (muhatap ile ayni sirkette iseniz ic musteri de diyebilirsiniz ama projeyi kullanacak taraf musteridir) ile kurdugunuz temaslarda net bilgileri alma zorlugu ve teslimde yasanan problemlerdi. Yazilimcilar musterinin dilini, musteri yazilimcinin dilini anlamadigi icin arada normalde olmasi gereken BA (Business Analyst) unvanli adamlar olmasi gerekirdi. Ben Turkiye'de pek rastlamadim ama normalde var bu unvan. 

Bunlar yapilacak isi dinleyip analiz edip etkilenecek diger yapilari inceleyip programciya projeyi yapilacak is parcalari seklinde ve adimlar halinde sunan adamlar. 

Iste BDD tam bu noktada devreye giriyor ve yukaridaki sistemdeki siralamalari degistiriyor. 

Analiz sirasinda, aslinda teslim'de istenen teslim kriterlerini ortaya koyarak bir nevi kabul testi olusturuyor ve projeyi bastan itibaren kabul kriterleri icinde gelistirmek uzere bir cerceve ciziyor. 

BDD ile duzyazi seklinde musterinin rahatlikla okuyunca anlayacagi is parcalari olusturuyor ve bunlarin uzerinde seneryolar uretiyoruz. Her biri rahatlikla okunabilen parcalar oldugundan (gercekten kod icermiyor) musteri ile mutabakat saglamak adina cok faydali bir adim. Ayni zamanda bu duzyazilar sizin testlerininzin sablonu ve TDD (Test Driven Development) icin bir cati anlamindalar. 

Boylece gelistirmedeki yontem soyle birseye donusuyor. 
1 - Analiz
2 - Tasarim, dokumantasyon ve test planlama
3 - Gelistirme ve Test
4 - Teslim 
5 -  Bakim

BDD icin TDD'yi de anlamak gerekiyor. TDD az da olsa kod icerdigi ve okunurken tam bir duzyazi olusturmadigi icin biraz daha programciya yakin bir kavram ama BDD tam ortada konumlanmis durumda. 

BDD icin en yaygin programlardan Cucumber ile tanismaya hazir miyiz ? 
http://cukes.info/ sitesinden ulasabileceginiz cucumber Ruby icin yazilmis olsa da .NET icin de kullanabilmenizi saglayan http://www.specflow.org/ gibi siteler de mevcut. Baska diller icin nasil kullanildigini google ile biraz arama yaparak bulabilirsiniz.

Gecen hafta tanistigim Matt Wynne Cucumber uzerine yazilmis iki kitabin da yazari.

Turkiye'de nasil elde edeceginizi bilemiyorum ama bu kitaplara ulasmak icin ipuclari bu blogda mevcut.

Kabul testleri yazildiginda dogal olarak hata verecektir. Cunku henuz kod yazilmamistir ancak musteriye de yazilimciya da sonucta ne olacagini anlatirlar.
Unit Test (birim test) kavrami ile karistirilmamasi gerekir. Birim test'i birseylerin dogru yapilmasini saglarken kabul testleri dogru birseylerin yapilmasini saglar. 

Testlerde onemli nokta da takimdaki herkes tarafindan anlasilacak ortak bir dil kullanilmasi gerektigidir. Cucumber'i guclu kilan yon de takimdaki herkes tarafindan testlerin kolaylikla yazilmasini saglayan dil yapisidir.

Asagida bir ornegini goruyorsunuz. Cucumber tarafindan kritik kelimeler bold ve kirmizi isaretlenmistir. Dilerseniz Turkce de kullanabilirsiniz. Nasil Turkce kullanilacagi hakkinda bilgi icin luten asagidaki linke bakiniz.

https://github.com/cucumber/cucumber/wiki/Spoken-languages
Feature: Sign up
  Sign up should be quick and friendly.

  Scenario: Successful sign up
    New users should get a confirmation email and be greeted
    personally by the site once signed in.
    Given I have chosen to sign up
    When I sign up with valid details
    Then I should receive a confirmation email
    And I should see a personalized greeting message

  Scenario: Duplicate email
    Where someone tries to create an account for an email address
    that already exists.
    Given I have chosen to sign up
    But I enter an email address that has already registered
    Then I should be told that the email is already registered
    And I should be offered the option to recover my password
Metin dosyalarinda basit birkac yazim kurali gecerlidir ki bu kurallara Gherkin deniyor

Bir diger fayda da kodlarin gercekten ne yaptigini yansitan dokumantasyonun (mecburen) guncel ve senkronize olmasi durumudur. Cunku ne degisiklik yapilmis olursa olsun bu dokumantasyon guncel olarak devam edecektir.

Nasil calistigina gelince; herseyden once cucumber bir komut satiri programidir. Sonu features diye biten metin dosyalarindan spesifikasyonlari okur. Senaryo bazinda testleri calistirir. Her senaryo Cucumber'in calisacagi test adimlarindan (step definition) olusur, boylece cucumber ne yapilacagini anlar. Bir seneryo icindeki adim tanimlari tek tek islenip hata ile karsilasilmazsa bir sonraki senaryoya gecerek teste devam edilir.

Cucumber calistirildiginda belli bir klasor duzeni icinde belli dosyalari gormek istiyor.
TestProjesi altinda klasor ve dosya yapilanmasi su sekilde olacaktir


Adim tanimlarini olusturma 

Basit bir toplama islemi icin su sekilde bir features dosyasi olusturup komut satirinda cucumber yazdiginizda 
Feature: Adding
  Scenario: Add two numbers
    Given the input "2+2"
    When the calculator is run
    Then the output should be "4"     

cucumber size asagidaki sekilde bir cikti verecektir.
cucumber
Feature: Adding
  Scenario: Add two numbers
    Given the input "2+2"
    When the calculator is run
    Then the output should be "4"  
1 scenario (1 undefined)
3 steps (3 undefined)
0m0.003s
You can implement step definitions for undefined steps with these snippets:
Given /^the input "([^"]*)"$/ do |arg1|
  pending # express the regexp above with the code you wish you had
end
When /^the calculator is run$/ do
  pending # express the regexp above with the code you wish you had
end
Then /^the output should be "([^"]*)"$/ do |arg1|
  pending # express the regexp above with the code you wish you had
end
If you want snippets in a different programming language,
just make sure a file with the appropriate file extension
exists where cucumber looks for step definitions.

Ortada yesil ile gosterdigim bolum cucumber'in bekledigi adim tanimlarinin bir ornegidir. bu bolumu kopyalayip features dizini altina olusturacaginiz step_definitions klasorunde bir ruby (veya hangi dil icin kullaniyorsaniz o dilin) dosyasina yapistirin.

Simdi cucumber calistirildiginda artik bize adim dosyasi uzerinde hangi adimda test'in kirildigini anlatmaya baslayacaktir.

Adim tanimlari icinde bol bol Regular Expression kullanildiginin farkindasinizdir. Bu da baska bir yazinin konusu olacak simdi ilk testi duzenliyoruz. Basitce verilen parametreyi degiskene atadik.

Given /^the input "([^"]*)"$/ do |input|
@input = input
end
cucumber bu asamada calisinca cikti farkli olacaktir.
Feature: Adding
  Scenario: Add two numbers
    Given the input "2+2"
    When the calculator is run
      TODO (Cucumber::Pending)
      ./features/step_definitions/calculator_steps.rb:9
      features/adding.feature:5
  Then the output should be "4"

1 scenario (1 pending)
3 steps (1 skipped, 1 pending, 1 passed)
0m0.002s
evet cucumber testlerin 1. adiminin gecildigini gosteriyor artik. Adim tanimlarina donup 2. adimi so sekilde duzenliyoruz.

When /^the calculator is run$/ do
    @output = `ruby calc.rb #{@input}`
    raise('Command failed!') unless $?.success?
end
tekrar cucumber calistirildiginda
Feature: Adding
  Scenario: Add two numbers
    Given the input "2+2"
    ruby: No such file or directory -- calc.rb (LoadError)
    When the calculator is run
    Command failed! (RuntimeError)
    ./features/step_definitions/calculator_steps.rb:10
    features/adding.feature:5
    Then the output should be "4"

Failing Scenarios:
cucumber features/adding.feature:3
1 scenario (1 failed)
3 steps (1 failed, 1 skipped, 1 passed)
0m0.027s
hata degisti artik boyle bir dosyanin olmadigi hatasini aliyoruz.

Mantik bu sekilde herhangi bir, asamada cucumber'i calistirarak bir sonraki asamda ne yapilmasi gerektigini goruyor ve adim adim projenizi ilerletebiliyorsunuz. Boylece her adimda hem kabul testine sadik kaliyor hem de istenilenlerin yapildigindan emin olarak ilerleyebiliyorsunuz.

Bu yazi kalabaligindan ziyade sorunu direk gormek istediginizde asagidaki gibi cucumber'i calistirabiliyorsunuz
cucumber --format progress
o zaman da cikti olarak asagidaki goruntuleniyor.
.ruby: No such file or directory -- calc.rb (LoadError)
F-

(::) failed steps (::)

Command failed! (RuntimeError)
./features/step_definitions/calculator_steps.rb:10
features/adding.feature:5

Failing Scenarios:
cucumber features/adding.feature:3 # Scenario: Add two numbers

1 scenario (1 failed)
3 steps (1 failed, 1 skipped, 1 passed)
0m0.023s
Program olmadan testlerin gecilebildigine dikkat etmissinizdir. testlerin bazilarinin gecilmis olmasi onemli degil sonucta tum projenin testi hatasiz bitirmesi onemli.
When /^the calculator is run$/ do
    @output = `ruby calc.rb #{@input}`
    raise('Command failed!') unless $?.success?
end

Birkac feature ornegi daha verelim
Feature: Feedback when entering invalid credit card details In user testing we've seen a lot of people who made mistakes entering their credit card. We need to be as helpful as possible here to avoid losing users at this crucial stage of the transaction.

Background:
  Given I have chosen some items to buy
  And I am about to enter my credit card details

  Scenario: Credit card number too short
    When I enter a card number that's only 15 digits long
    And all the other details are correct
    And I submit the form
    Then the form should be redisplayed
    And I should see a message advising me of the correct number of digits

  Scenario: Expiry date invalid
    When I enter a card expiry date that's in the past
    And all the other details are correct
    And I submit the form
    Then the form should be redisplayed
    And I should see a message telling me the expiry date must be wrong
Ozelliklerin yazildigi Gherkin dilindeki anahtar kelimeler (ingilizce olanlari)
• Feat ure
• Background
• Scenario
• Given
• When
• Then
• And
• But
• *
• Scenario Outline
• Examples
Turkceleri ise

         "feature": "Özellik",
         "background": "Geçmiş",
         "scenario": "Senaryo",
         "scenario_outline": "Senaryo taslağı",
         "examples": "Örnekler",
         "given": "*|Diyelim ki",
         "when": "*|Eğer ki",
         "then": "*|O zaman",
         "and": "*|Ve",
         "but": "*|Fakat|Ama"
Sadece Gherkin'de yazilanlarin dogrulugunu test etmek ama programi test etmek istemediginizde asagidaki komutu verebiliyorsunuz.
cucumber test.feature --dry-run
yukaridaki anahtar kelimelerin fonksiyonlarina gelince

Feature 

Pek bir anlam ifade etmiyor sadece ozelligin aciklamasinda kullanilan terimlerin basina geliyor ve aciklamalar birkac satirdan olusabiliyor.

Ardindan su anahtar kelimelerden biri gelmek zorunda
• Scenario
• Background
• Scenario Outline

Nereden baslanacagini bilemediginiz ozellikler icin soyle bir kalip kullanmak faydali olabilir

In order to <meet some goal>
As a <type of stakeholder>
I want <a feature>
Bir de yine de aralara yorum yazmak isterseniz # isaretini kullanabilirsiniz. 

Scenario

istedigimiz davranis(lar)in anlatilmasi icin bunu kullaniyoruz. Senaryolar projenin sinirlarini cizmek icin kullanilir ve su sekilde bir yol izlerler.
1 - Sistemi belli bir duruma getir
2 - durt, gidikla birseyler yap
3 - Yeni durumu incele

Senaryolari yazarken cok onemli bir husus var : 

Her senaryo mantikli olmali ve bagimsiz olarak tek basina calistirilabilir olmalidir. 

Yani bir senaryoda para yatirip digerinde cekmeniz isin dogasina aykiri. (hata olarak degerlenmiyor ama yanlis)

Senaryo isimlerinin duzgun verilmesi zaman kazanmak icin onemlidir. Boylece feature dosyasi icindeki kodlari okumadan probleme odaklanma, sonradan bakim yapmayi kolaylastirma gibi faydalar yaratacaktir.

Given, When , Then

Senaryolarda izlenecek yolu belirlemede kullanilirlar.

Scenario: Successful withdrawal from an account in credit
  Given I have $100 in my account # the context
  When I request $20 # the event(s)
  Then $20 should be dispensed # the outcome(s)

And, But

Senaryolardaki adimlari artirmak icin killanilabilecek yapilardir. Sadece okunabilirligi artirmak icin kullanilir . Ornegin asagidaki iki senaryo birbirinin aynisidir. Hatta bunlarin tamami yerine * kullanmak da mumkundur.

Scenario: Attempt withdrawal using stolen card
  Given I have $100 in my account
  But my card is invalid
  When I request $50
  Then my card should not be returned
  And I should be told to contact the bank


Scenario: Attempt withdrawal using stolen card
  Given I have $100 in my account
  Given my card is invalid
  When I request $50
  Then my card should not be returned
  Then I should be told to contact the bank

Her bir asamanin yerinin dogru anlasilmasi icin yandaki sekil aciklayici olacaktir. 

Birkac Ipucu

Given a User "Michael Jackson" born on August 29, 1958
And a User "Elvis" born on January 8, 1935
And a User "John Lennon" born on October 9, 1940

Yerine su sekilde kullanimlar mumkun

Given these Users:
| name                  | date of birth         |
| Michael Jackson | August 29, 1958  |
| Elvis                   | January 8, 1935   |
| John Lennon      | October 9, 1940   |

veya
Then my shopping list should contain:
| Onions |
| Potatoes |
| Sausages |
| Apples |
| Relish |

Then I should see a vehicle that matches the following description:
| Wheels | 2 |
| Max Speed | 60 mph |
| Accessories | lights, shopping basket |



Sonucta size tamamini veya butun ipuclarini gosteremesem de mumkun oldugunca BDD ve Cucumber konusunu aktarmaya calistim. Bu arada bu yazida cokca yararlandigim Matt Wynne ve Aslak Hellesøy'un The Cucumber Book kitabini tekrar tavsiye ediyorum


Neden mi cucumber? Testleri gectikce yazilar yesile dondugu icinmis. 
Turkce kullanmak icin cucumber --i18n tr kullanabilirsiniz

2 yorum:

  1. emeğinize sağlık, mükemmel bir paylaşım olmuş.

    YanıtlaSil
  2. Emeğinize sağlık, paylaşım çok değerli..

    YanıtlaSil