ตัวอย่างการทำ Unit Test แบบง่ายๆ

หลายครั้งที่ผมได้ยินคำว่าให้ทำ unit test ผมมักจะพบว่า โปรแกรมเมอร์(ผมด้วย) จะใช้วิธีรันโปรแกรมแล้วกรอก input หรือทำตาม step ที่ต้องทดสอบ ถ้าพบ bug ก็แก้ code จนได้ผลลัพท์ที่ต้องการก็จบแล้วก็ส่งขึ้น build เพื่อให้ tester ตรวจสอบต่อไป

จากเหตการณ์ที่กล่าวมา เราลองมาแปลความหมายของคำว่า Unit Test กัน ถ้าให้ยึดตามความหมายตาม wikipedia ความหมายของ Unit เขาเขียนไว้ดังนี้

A unit is the smallest testable part of an application

มันคือหน่วยที่เล็กที่สุดของโปรแกรมที่สามารถทดสอบได้ แล้วที่เรารันโปรแกรมเพื่อทดสอบหน่ะเหรอเรียกว่าหน่วยย่อยของโปรแกรม ก็เลยเป็นที่มาของบล็อกนี้ เพื่อแสดงวิธีการเขียน Unit Test ด้วย JUnit

Tool ที่ผมใช้

  1. JDK 6
  2. Eclipse Indigo

กรณีตัวอย่าง คลาสจัดรูปแบบการแสดงผลของ Date object

ผมสร้างคลาส DateFormatUtil ขึ้นมา ทีนี้ผมต้องการทดสอบคลาสที่เพิ่งเขียนนี้ ถ้าเอาง่ายเลยก็คงเขียนเมธอด main แล้วก็เรียกดู วิธีนี้ได้ผลแต่ก็ลูกทุ่งไป เพราะบางทีหากมีการแก้ไข pattern โดยคนอื่น อาจจะได้ผลลัพท์ที่เราคาดไม่ถึงก็ได้ วันนี้ผมเลยขอเสนอ JUnit มาเป็นพระเอกให้

เริ่มต้น JUnit บน Eclipse

  1. สร้าง Java Project ขึ้นมาแล้วสร้างคลาส DateFormatUtil ดังนี้
    package util;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class DateFormatUtil {
    	
    	public String parseSimpleThaiFormat(Date date){
    		SimpleDateFormat formatter = new SimpleDateFormat("dd/MMM/yyyy");
    		return formatter.format(date);
    	}
    }
    
  2. สร้าง source folder ชื่อ test (คลิกขวาชื่อโปรเจคแล้วเลือก new -> source folder) เพื่อแยกคลาส Test ออกจากคลาสหลัก
  3. ที่หน้าต่าง Package Explorer คลิกขวาที่ชื่อไฟล์ DateFormatUtil -> New -> JUnit Test Case (ถ้าไม่พบให้เลือก Other แล้วพิมพ์ค้นหาเอา) จะมี dialog ดังนี้
    1 - new test case

    ที่ช่อง Source folder กดปุ่ม Browse… แล้วเลือก folder test ที่เราเพิ่งสร้างจากขั้นตอนที่แล้ว จากนั้นกด Next
    2 - select method
    เลือกเมธอด parseSimpleThaiFormat แล้วกดปุ่ม Finish หากยังไม่เคยมีการเพิ่ม Library ของ JUnit จะมี Dialog ขึ้นมาถามให้เพิ่มด้วยหรือเปล่า ก็กดปุ่ม OK ได้เลย เมื่อ Eclipse ทำงานเสร็จก็จะได้คลาสหน้าตาดังนี้

    package util;
    
    import static org.junit.Assert.*;
    
    import org.junit.Test;
    
    public class DateFormatUtilTest {
    
    	@Test
    	public void testParseSimpleThaiFormat() {
    		fail("Not yet implemented");
    	}
    
    }
    
    
  4. ผมแก้ไข Test Case ใหม่ดังนี้
    package util;
    
    import static org.junit.Assert.*;
    
    import java.util.Calendar;
    import java.util.GregorianCalendar;
    
    import org.junit.Test;
    
    public class DateFormatUtilTest {
    
    	@Test
    	public void testParseSimpleThaiFormat() {
    		DateFormatUtil format = new DateFormatUtil();
    		Calendar calendar = new GregorianCalendar();
    		calendar.set(2012, 0, 25);
    		assertEquals("25/01/2555", format.parseSimpleThaiFormat(calendar.getTime()));
    	}
    
    }
    
    

    เคสที่ผมผมคาดหวังว่า เมื่อส่งวันที่ 25 เข้าในแปลง ผมจะได้ตามที่ผมต้องการ (บรรทัดคำสั่ง assertEquals) จากนั้นคลิกขวาที่คลาสนี้แล้วเลือก Run As -> JUnit Test จะปรากฏหน้าจอดังนี้
    3 - first fail
    สั้นๆ ว่างานเข้าครับทดสอบไม่ผ่าน ที่ช่อง Failure Trace แจ้งว่า ผลลัพธ์ที่ผมคาดหวังไว้ไม่ตรงกับที่คลาสตอบกลับมา ต่อไปก็เป็นหน้าที่เราที่จะต้องแก้โปรแกรมให้ตรงตามที่เราคาดหวังไว้หล่ะ

  5. แก้คลาส DateFormatUtil ใหม่ได้ดังนี้
    package util;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Locale;
    
    public class DateFormatUtil {
    	
    	public String parseSimpleThaiFormat(Date date){
    		Locale.setDefault(new Locale("th", "TH"));
    		SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
    		return formatter.format(date);
    	}
    }
    
    

    จากนั้นกลับไปรัน Test Case ใหม่ ควรจะได้หน้าจอดังนี้
    4 - success
    ไฟเขียวแสดงว่าผ่าน เฮ้!!!

  6. แต่ชีวิตจริงมันไม่ง่ายขนาดนั้น เพราะว่าเราทดสอบยังไม่ครอบคลุม ซึ่งผมก็ได้เพิ่ม Case ส่งค่า null เข้าไปเพื่อทดสอบ
    package util;
    
    import static org.junit.Assert.*;
    
    import java.util.Calendar;
    import java.util.GregorianCalendar;
    
    import org.junit.Test;
    
    public class DateFormatUtilTest {
    
    	@Test
    	public void testParseSimpleThaiFormat() {
    		DateFormatUtil format = new DateFormatUtil();
    		Calendar calendar = new GregorianCalendar();
    		calendar.set(2012, 0, 25);
    		
    		assertEquals("-", format.parseSimpleThaiFormat(null));
    		assertEquals("25/01/2555", format.parseSimpleThaiFormat(calendar.getTime()));
    	}
    
    }
    

    ผมคาดหวังว่า ถ้าส่งค่า null เข้าไปจะได้เป็นเครื่องหมายขีดกลับมา จากนั้นรัน Test Case ใหม่ก็จะพบหน้าจอนี้
    5 - NullPointerException
    ร้องเบาๆ ว่า งานเข้าแล้วตรู ก็ไม่ได้เขียนให้รองรับนิหน่า ก็กลับไปแก้ไขโปรแกรมให้รองรับ Case ค่าวันที่เป็น Null ดังนี้

    package util;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Locale;
    
    public class DateFormatUtil {
    
    	public String parseSimpleThaiFormat(Date date) {
    		String formatDate = "-";
    		if(date != null){
    			Locale.setDefault(new Locale("th", "TH"));
    			SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
    			formatDate = formatter.format(date);
    		}
    		return formatDate;
    	}
    }
    

    จากนั้นก็รัน Test Case ใหม่ ควรจะขึ้นไฟเขียว

สรุป

จากนี้ไป เราก็สามารถมั่นใจได้ว่าคลาสเราทำงานได้ถูกต้องด้วยการรัน Test Case นี้ทุกครั้งที่มีการ Update โค้ดจากคนอื่น ซึ่งหากผลการรัน Test Case ไม่ผ่านก็สามารถหาต้นตอเจอได้ว่าผิดที่ตรงใหน

จะเห็นได้ว่า การทำ Unit Test ไม่ยากอย่างที่คิด สิ่งที่ยากคือเราออกแบบคลาสให้รองรับการทำ Unit Test ได้หรือเปล่า ตอนต่อไปผมจะทำตัวอย่างการทำ Unit Test ด้วย JUnit ของ Java Web Project ให้ชม โปรดติดตามตอนต่อไป

3 thoughts on “ตัวอย่างการทำ Unit Test แบบง่ายๆ

  1. สุดยอดครับ เห็นภาพเลยครับ ประหยัดเวลาไปเยอะเลย ขอบคุณมากครับ

  2. ขอบคุณมากครับสำหรับตัวอย่างการทำ unit test ทำให้ผมมองเห็นภาพเลยครับว่ามีกระบวนการอย่างไร แต่น่าเสียดายที่ตอนนี้ผมกำลังหาเครื่องมือช่วยทำ unit test กับ javascript แต่ยังไงก็ขอบคุณมากครับ

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s