Displaying articles with tag testing

Rspec Autotesting with Growl

Posted by PunNeng, Wed Oct 03 03:00:00 UTC 2007

ก่อนจะทำการ test ด้วย Rspec ก็็ต้องมีเครื่องมือช่วยกันหน่อย
ผมขอเลือกสภาพแวดล้อมที่เห็นว่ามันดีที่สุดละกันในการ test คือ ทำบน OS X แล้วใช้ tool ที่มหัศจรรย์อย่าง autotest ของ ZenTest และ Growl มาช่วย และอีกหนึ่งอย่างที่ผมชอบคือ RedGreen สำหรับ highlight ผลการ test บน terminal

ติดตั้งก่อน

$ sudo gem install rspec zentest redgreen
แล้ว download growl มาติดตั้ง
$ open Growl-0.7.x.dmg
$ cd /Volumes/Growl/Extras/growlnotify
$ sudo ./install.sh
แล้วเพิ่ม PATH ตามที่มันบอกมาด้วย ยังไม่จบ ไป download icon สวยๆ มาก่อน จากที่นี่ก็ได้ หรือใครอยากได้เสียง ก็ลองหาโหลดดูครับ สมมติว่าโหลดมาเสร็จแล้ว extract จาก zip file เรียบร้อยแล้ว
$ mv your_image_path/autotest_images ~/.autotest_images
$ nano .autotest
ใส่ไปว่า
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
module Autotest::Growl

  Autotest.add_hook :ran_command do |at|
    if at.results.empty? # break out gracefully if a test file throws an uncaught exception
      growl( "Syntax error", "", '~/.autotest_images/fail.png')
    else
      output = format_input( at.results )
      display_notification( output )
    end
  end

  private

  def self.growl title, msg, img, pri=0, stick="" 
    system "growlnotify -n autotest --image #{img} -p #{pri} -m #{msg.inspect} #{title} #{stick}" 
  end

  # isolate the example, failure, pending line like "12 examples, 4 failures, 5 pending"
  # and remove color codes
  def self.format_input( input )
    output = input.detect{ |result| result.include? "example"}
    output = remove_color_codes( output )
  end

  def self.display_notification( output )
    examples, failures, pending = output.split(", ")
    if failures.to_i > 0
      # uncomment a line below for sound
      # system "~/bin/sndplay ~/your/sound/path/failed.wav -volume 0.5"
      growl( "Tests Failed", output, '~/.autotest_images/fail.png', 2 )
    elsif pending.to_i > 0
      growl( "Tests Pending", output, '~/.autotest_images/pending.png', 1 )
    else
      growl( "Tests Passed", output, '~/.autotest_images/pass.png', 0 )
    end
  end


  def self.remove_color_codes( string )
    string.match( /m(.+)\e/)[1]
  end
end
ต้องติดตั้ง rpec ของ rails ก่อน
ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec
ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec_on_rails

หรือเพิ่ม -x ไป ถ้าใช้ subversion

แล้วมาลอง test เล่นๆ สักอัน

$ cd /your/app
$ ruby script/generate rspec
$ ruby script/generate rspec_scaffold article
$ rake
$ autotest

สั่งสร้างค่าพื้นฐานของ rspec ก่อน
แล้วสร้าง spec ของ resource ที่เรากำลังจะพิจารณา ซึ่งตอนนี้ ผมใช้ edge rails อยู่ ได้มีการ update อะไรหลายๆ อย่าง หนึ่งในนั้นคือ generator ซึ่ง scaffold จะทำการสร้างค่าพื้นฐานของ restful ไว้เลย
สั่ง rake เพื่อสร้างค่าพื้นฐานของสภาพแวดล้อมสำหรับ test
แล้วก็สั่ง autotest เพื่อเรียกให้ autotest ทำงาน

เปิด file ใน มาแก้สักตัว ก็น่าจะเห็น growl มันทำงาน และ การเปลี่ยนแปลงใน terminal

ก็มี screen shot เล็กๆ น้อย ให้ดูสำหรับ growl กับใน terminal
อันนี้ผมรันครั้งแรก

Test Failed

แล้วก็แก้ไขอะไรเล็กน้อยให้มันผ่าน

test_passed

แล้วก็ลองเพิ่ม spec แต่ยังไม่ได้ implement

test_pending

ข้อมูลจาก
internaut
Growl Notifier from Mike Vicent

0 comments | Filed Under: Ruby on Rails | Tags: testing

Behavior Driven Development

Posted by PunNeng, Thu Sep 20 04:56:00 UTC 2007

จริงๆ เรื่องการ test บน Rails เนี่ย ผมกะว่าจะเขียนมานานละ
ช่วงนั้นมี Test Driven Development(TDD) กำลังแรงจาก Extreme programming ไอ้ผมก็เขียน test case บน Rails ก็ปกติดี แต่บังเอิญว่า Behavior Driven Development(BDD) เพิ่งเกิดพอดี เลยยังลังเลว่าจะเขียนเรื่องนี้เลยดีไหม

พอดีเจ้านายผมอยากให้เขียน test ในลักษณะที่รวมสิ่งแวดล้อมรอบด้านด้วย ใน 1 test case ของผมเลยค่อนข้างจะรุงรัง เช่น การ login ก็ตรวจมันตั้งแต่การ validate, login ผ่านหรือเปล่า สมมติว่าผ่าน ต้องจำค่า user เอาไว้แล้ว redirect ไปไหน?? หรืออีก test case นึง กรณีที่ไม่ผ่าน จะ redirect ไปไหน มันก็เลยดูเกินความหมายของคำว่า unit test ไปหน่อย

แล้วก็บังเอิญไปเจอ BDD พอดี ไปเจอ Rspec เข้าให้ ผมกับเจ้านายเลยคิดว่า ไอ้ตัวนี้แหละ ที่เราต้องการ !!! ผมก็เลยเอาไว้ก่อน ให้มันโตมากกว่านี้หน่อย ค่อยเขียน แล้วมันก็สุกงอมพอดี ตอนนี้กระแสที่รุนแรงที่สุดของ Rails คือการทำ BDD ด้วย Rspec นี่แหละ

ทำไมถึงต้องการ ??

BDD มันเกิดมาจากการเรียนรู้จาก TDD
โปรแกรมเมอร์ที่ใช้ TDD เริ่มจะมองเห็นมากกว่าการเป็น unit test คือ เห็นว่าการเขียน test ก่อนเขียน code จะทำให้เรารู้ว่า code ที่จำเป็นมันน่าจะเป็นยังไง หรือเห็น process ของงาน จากนั้นก็เริ่มเห็นความเป็นพฤติกรรม ซึ่งพวกเขาก็เชื่อว่าพฤติกรรมนี่แหละ เป็นหัวใจของ process

ทางทีมที่คิด BDD ขึ้นมา เลยเริ่มผลักดันให้มันเกิดขึ้นมา เพราะเห็นว่าโปรแกรมเมอร์ที่เขียน test คงจะมองเห็นถึงจุดการเป็นพฤติกรรมเนี่ย ไม่เยอะเท่าไหร่ อยากจะให้คนกลุ่มนี้ เข้าถึงแนวความคิดอันนี้

BDD จึงมีจุดประสงค์ให้โปรแกรมเมอร์หรือนักพัฒนา เน้นไปที่การมองว่ามันจะมีพฤติกรรมยังไงมากกว่าการ test ซึ่งจะช่วยให้เข้าถึงตัวงานจริงๆ ได้ตรงและเร็วที่สุด

ซึ่งแบบที่เจ้านายผมให้ผมเขียน test ใน test case นั่นแหละ มันดูเป็นพฤติกรรมตามแนวความคิดของ BDD เลย มันเลยโป๊ะเช้ะ

BDD มันมีพื้นฐานมาจากการดูที่พฤติกรรมเป็นหลัก ถ้าเราตั้งคำถามว่า

Login controller ควรจะทำอะไรได้บ้าง ?

ผมก็จะตอบว่า

มันควรจะ login ได้ปกติ
มันควรจะ login ได้ปกติ และจำไว้(remember me) ด้วย
มันควรจะ login ไม่ได้ เพราะ password ผิดหรือไม่มี username นั้นๆ
มันควรจะ logout ได้

เราจะมามองกันที่พฤติกรรมเป็นหลัก

ถ้าเราตอบได้หมดว่า Login controller ควรจะมีพฤติกรรมอะไรบ้าง นั่นก็น่าจะเป็นสิ่งที่เราต้องการและต้องพัฒนาทั้งหมดแล้ว เห็นภาพรวมหมดทั้งกระบวณการ

ถ้าจะให้กระบวณการ(พฤติกรรม)มันมีความถูกต้อง ก็คงต้อง test มัน(ก่อน)ละครับ สำหรับ Ruby/Rails คงต้อ Rspec นี่แหละครับ ที่ช่วยได้

แล้วยังไงจะมาลอง implement ให้ดูครับ :)

ข้อมูลจาก
Test-driven development - Wikipedia, the free encyclopedia
Introduction - Behaviour-Driven Development

1 comment | Filed Under: General | Tags: testing

codegent: we're hiring