การทดลองที่ 6 JUnit

Lab ครั้งนี้ จะทำความรู้จักกับ JUnit ซึ่งเป็น Unit testing framework สร้างโดย Erich Gamma หนึ่งในเจ้าพ่อหนังสือ design pattern - gang of four (ไม่ใช่ Fantastic Four นะ) อ่านเพิ่มเติมได้ที่  http://hillside.net/patterns/DPBook/GOF.html

ขอให้ลองคิดดูว่า หากเราต้องเขียนโปรแกรมขนาดใหญ่และมีความซับซ้อนสูง เราจำเป็นอย่างยิ่งที่ต้องทดสอบว่าสิ่งที่เราเขียนไปนั้นถูกต้องหรือไม่ หรือมี Bug อันไม่น่าพึงประสงค์หลบซ่อนอยู่หรือไม่ เป็นระยะๆ ไม่ใช่เขียนจนเสร็จ แล้วค่อยมาทดสอบโปรแกรมทีเดียวเลย บ่อยครั้งที่เราหา bug ไม่เจอ แล้วเราต้องเขียนโปรแกรมใหม่ทั้งหมดตั้งแต่เริ่มต้นใหม่

ถ้าพร้อมแล้ว เรามาเริ่มกันเลย

 

1. เปิด Eclipse ขึ้นมา

2. New > Project แล้วสร้างโปรเจคใหม่ชื่อ  HelloJUnit ขึ้นมา

3. สร้าง Class ใหม่ขึ้นใน Project ชื่อว่า HelloWorld ตรง Package ให้ใส่ว่า HelloJUnit แล้วกด Finish ได้เลย

4. เอา Code นี้ลงไปใส่เลย

 

package HelloJUnit;

 

public class HelloJUnit {

               

                public HelloJUnit(){}

               

                public String say(){                            

                                String s = "Hollow JUnit!";

                                return s;                               

                }

}

 

(เห็นอะไรแปลกๆใน code ข้างบนมั้ย ... ให้แกล้งทำเป็นไม่เห็นไปซะ)

ลองคิดดูชีวิตจริง หากหลังจากเขียน Class ข้างบนเสร็จ เราเองก็คิดว่า เสร็จแล้ว ส่งงานได้แล้วล่ะแบบนี้ หายนะแน่ๆ จะดีกว่ามั้ย ถ้าเราใช้ JUnit ของเรา ทดสอบซะหน่อย

1.เปิด New > JUnit Test Case ดังรูป

(หรือถ้าหาไม่เจอ ให้เลือก Other…  > Java > JUnit > JUnit Test Case ก็ได้)

โดยใส่ Package เป็น HelloJUnit และใส่ชื่อ Class ว่า TestHelloJUnit

 

จะสังเกตเห็นว่าโปรแกรมมันไม่รู้จัก JUnit ในตอนนี้ เราต้องทำการ Add JUnit Library ก่อน ดังนี้

          ที่ Project > Property > Java Build Path ภายใต้ Tab ชื่อ Library ให้เลือก Add Library > JUnit > JUnit 3.8.1 ดังรูป

จากนั้น กด OK เท่านี้ เราก็พร้อมจะใช้ JUnit ได้แล้ว

 

ที่ Class TestHelloJUnit ให้ใส่ Code ดังนี้

package HelloJUnit;

 

import junit.framework.TestCase;

 

public class TestHelloJUnit extends TestCase {

               

    private HelloJUnit hi;

               

    public TestHelloJUnit (String name) {

        super(name);

    }

  

    public void testSay() {

        hi = new HelloJUnit();

        assertEquals("Hello JUnit!", hi.say());

    }  

}

ที่ Method ชื่อว่า testSay() ตรงนี้นี่เอง ที่เราจะทำการทดสอบ Method Say() ของ Class HelloJUnit ว่า ทำงานได้ถูกต้องหรือไม่

 

ตรงบรรทัดที่เขียนว่า

assertEquals("Hello JUnit!", hi.say());

จะทำการทดสอบว่าโปรแกรมเรา ทำงานได้ถูกหรือไม่ (ดูก็รู้ ว่ามันต้องไม่ถูกแน่ๆ)

 

เรามาลองสั่งให้ JUnit ทำการ Testing กัน

ให้ไปที่ Run > Run… จะปรากฏหน้าต่างดังรูป

ที่ด้านซ้าย ให้เลือก JUnit (ย้ำ ว่า JUnit ไม่ใช่ Java Application นะ)

เลือก Test class ให้เป็น TestHelloJUnit ดังรูป แล้วกด Run

 

ให้ดูทางด้านซ้ายมือสุด ด้านล่าง (Failure Trace) จะเห็นว่ามีข้อผิดพลาดอยู่

 

ลอง Double Click ตรงแถบน้ำเงินดังรูปดู มันจะฟ้องเรามา Assert ใน TestHelloJUnit ใดที่จับผิด HelloJUnit ได้ เราเราก็กลับไปแก้ที่ผิดนั้น

 

คราวนี้ ลองกลับไปที่ คลาส HelloJUnit แล้วเปลี่ยน

"Hollow JUnit!" เป็น "Hello JUnit!" ดู แล้ว Run JUnit ใหม่

(ตอนนี้ กดปุ่ม Run ที่แถบ Menu Bar เลยก็ได้ เพราะว่ามันจำการสั่ง Run ครั้งที่แล้วไว้)

จะได้ผลดังรูป

สังเกตดูว่า แถบสีแดงในตอนแรกกลายเป็นสีเขียวแล้ว และ Failure Trace ก็ไม่มีแล้วด้วย

เท่านี้เราก็สบายในได้แล้ว เพราว่าโปรแกรมของเราทำงานได้ถูกต้องแล้ว

 

*** ให้สังเกตว่า ทุก Test Case จะต้องขึ้นต้นชื่อด้วยคำว่า Test เสอม เช่น จะทดสอบเมทอด Say() ก็ต้องตั้งชื่อ Test Case ว่า testSay() เป็นต้น

 

ต่อมาลองเพิ่ม Code ในส่วนของคลาส HelloJUnit เป็นดังนี้

package HelloJUnit;

 

public class HelloJUnit {

               

                public HelloJUnit(){}

               

                public String say(){            

                                String s = "Hello JUnit!";

                                return s;               

                }

               

                public String shout(){        

                                String s = "!!!HELLO JUNIT!!!";

                                return s;               

                }

               

                public String whisper(){     

                                String s = "... hello JUnit ...";

                                return s;               

                }

               

}

 

ตอนนี้เรามี 4  เมทอดแล้วล่ะ .... ถึงเวลาทำงานแล้วครับ ....

ไหนลองเขียน Code ใน TestHelloJUnit เพิ่มเติม เพื่อทดสอบ เมทอดใหม่ของเราดูซิ

1.     testShout()

2.     testWhisper()

เขียนให้เสร็จ จากนั้นลงไปดู เฉลยข้างล่าง

 

 

 

................  แน่ใจเหรอ ว่าเขียนเสร็จแล้ว อย่าใจร้อนลงไปดูเฉลย ก่อนนะ ........................

 

 

 

 

อ่ะ ... ดูเฉลยครับ ...

package HelloJUnit;

 

import junit.framework.TestCase;

 

public class TestHelloJUnit extends TestCase {

               

                private HelloJUnit hi;

               

    public TestHelloJUnit (String name) {

        super(name);

    }

  

    protected void setUp() {

                hi = new HelloJUnit();

    }

   

    public void testSay() {    

        assertEquals("Hello JUnit!", hi.say());

    }

   

    public void testShout() {    

        assertEquals("!!!HELLO JUNIT!!!", hi.shout());

    }

   

    public void testWhisper() {    

        assertEquals("... hello JUnit ...", hi.whisper());

    }

       

    protected void tearDown() {

        hi = null;

    }

}

 

เห็นมั้ยครับ ว่ามีอะไรแตกต่างกันกับ Code ที่เราเขียนไหม

นั่นก็คือการเอา setUp() และ tearDown() มาใช้  นั่นคือ แทนที่เราจะต้องทำขั้นตอน

hi = new HelloJUnit(); ซ้ำๆทุกครั้ง เราก็ทำครั้งเดียวเลย ที่ SetUp()

ส่วน tearDown() นั้นก็คือสิ่งที่ควรทำหรือต้องทำ หลังจาก Test เสร็จแล้วนั่นเอง

 

JUnit แต่ละหน่วย เวลาจะทดสอบจะต้องถูกแยกทดสอบจากกันอย่างอิสระ ผลการทดสอบ unit หนึ่ง จะต้องไม่ส่งผลกระทบ หรือสร้างการขึ้นต่อกันต่ออีก unit หนึ่ง เพราะฉะนั้นหากเราใช้ตัวแปรร่วมกันระหว่าง unit ต่างๆ ตัวแปรเหล่านั้น ควรจะถูก reset ค่ากลับไปยังค่าตั้งต้นเสมอ ส่วนการ teardown จะเอาไว้ใช้ในกรณีหากใน setup มีการไปเรียกใช้ resource ภายนอก เช่นการติดต่อ IO ส่วน teardown ก็จะเป็นที่ไว้เก็บงานเช่น close IO connection ที่เปิดค้างเอาไว้ จากตัวอย่างที่ยกมา  เวลาสั่ง run ทั้ง class มันจะทำงานอย่างนี้ครับ

 

setUp();

testSay();

tearDown();

 

setUp();

testShout();

tearDown();

 

setUp();

testWispher();

tearDown();

 

 

ทีนี้ เราจะมาทำความรู้จักกับ Test Suite กัน

Test Suite คือการนำ Test Case หลายๆอัน มา Run พร้อมกันนั่นเอง

เรามาลองใช้ Test Suite กัน

 

ให้ New > Other…  > Java > JUnit > JUnit Test Case เพื่อเพิ่ม Test Case ใหม่อีกอันชื่อว่า TestArrayList โดยใส่ Package เป็น HelloJUnit เหมือนเดิม จากนั้นใส่ Code ลงไปดังนี้ครับ

package HelloJUnit;

import junit.framework.TestCase;

 

public class TestArrayList extends TestCase {

 

     private java.util.List myList;

 

     protected void setUp() {

         myList = new java.util.ArrayList();

     }

 

     protected void tearDown() {

          myList = null;

     }

 

     public void testNoElement() {

          assertEquals("Empty list should have 0 elements", 0, myList.size());

     }

 

     public void testForException() { 

                 

                 Object o = myList.get(0);

                 /*

          try {

               Object o = myList.get(0);

               fail("Should raise an IndexOutOfBoundsException");

          }

          catch (IndexOutOfBoundsException success) {

          }  

          */

     }

}

 

ทีนี้ เราก็มี Test Case 2 อันแล้ว

 

ต่อไปให้  New > Other…  > Java > JUnit > JUnit Test Suite โดยใช้ชื่อว่า AllTest โดยใส่ Package เป็น HelloJUnit เหมือนเดิม

สังเกตว่า ระบบจะ Generate Code ออกมาให้เลย ดังนี้ครับ

package HelloJUnit;

import junit.framework.Test;

import junit.framework.TestSuite;

 

public class AllTests {

 

                public static Test suite() {

                                TestSuite suite = new TestSuite("Test for HelloJUnit")

                                //$JUnit-BEGIN$

                                suite.addTestSuite(TestThatWeGetHelloWorldPrompt.class);

                                suite.addTestSuite(TestArrayList.class);

                                //$JUnit-END$                    

                                return suite;

                }

}

 

จากนั้นลองสั่ง Run ตัว AllTest ดู (วิธีการ Run ต้องไปที่ ให้ไปที่ Run > Run… จะปรากฏหน้าต่างดังรูป เราต้องเลือก Test Class โดยกดที่ปุ่ม Search… แล้วเลือก AllTest ด้วยนะ)

 

          จะพบว่ามีบางอย่างที่ผิดพลาดอยู่ใน Code ลงไปดูตรงนั้นกัน

 

          ตรงที่ testForException นั้น ลองอ่าน Code ดู จะเห็นว่าขณะนี้ myList ของเรา ยังว่างอยู่เลย ไม่มี Element ใดๆภายใน แบบนี้ถ้าเราไปเรียก Get() มันก็ต้องร้องสิ ว่ามี Exception เกิดขึ้น วิธีแก้ ให้เปลี่ยน Code เป็นดังนี้

public void testForException() { 

                 

                 //Object o = myList.get(0);

                 

          try {

               Object o = myList.get(0);

               fail("Should raise an IndexOutOfBoundsException");

          }

          catch (IndexOutOfBoundsException success) {

          }           

     }

 

          สังเกตที่ Fail() เป็น Method ที่ใช้ในการทำ Test ด้วย JUnit อีกแบบ (คล้ายๆกับ Assert นั่นล่ะ) ใช้ในการทดสอบ Exception ต่างๆ

          คราวนี้ ลอง Run ตัว AllTest ดูอีกที ว่าทดสอบทุกอย่างเรียบร้อยด้วยดีไหม ให้สังเกตหน้าต่างด้านซ้ายมือ ทุกอย่างที่เรียบร้อยแล้ว น่าจะออกมาหน้าตาคล้ายๆแบบนี้

 

ถึงตอนนี้ หวังว่าคงจะใช้ JUnit Test Case และ JUnit Test Suite กันเป็นแล้วนะ ถ้าอยากศึกษาเกี่ยวกับ JUnit เพิ่มเติม ให้ลองแวะไปดูที่ www.junit.org

 

สำหรับผู้ที่ต้องการ Online Document ให้ดูที่ http://junit.sourceforge.net/javadoc/junit/framework/Assert.html

 

 

ต่อมา จะสอนเกี่ยวกับ Recursive Programming สักเล็กน้อย เพื่อจะได้นำไปใช้ในการเขียนโปรแกรม สำหรับทำงาน

Recursive Programming เป็นวิธีการเขียนโปรแกรมแบบหนึ่ง ซึ่งมีการเรียกใช้ตัวเอง (ฟังแล้วอาจจะงง เดี๋ยวไปดูตัวอย่างละกัน) ซึ่งมีประโยชน์มาก เพราะการเขียนโปรแกรมบางอย่าง อาจเขียนแบบธรรมดาได้ยาก หรืออาจเขียนไม่ได้เลยถ้าไม่ใช้เทคนิคนี้ในการเขียน

ตัวอย่างเช่นถ้าเราต้องการเขียนโปรแกรมn หรือก็คือ n + (n-1) + (n-2) + … 1 เราอาจเขียนได้ 3 วิธี ได้แก่

1.     เขียนโปรแกรมโดยใส่สูตร Close Form ไปเลย เพราะเรารู้อยู่แล้ว ว่าn = n*(n-1)/2 ซึ่งวิธีนี้ ด็ดูดี สำหรับสูตรที่เรารู้ Close Form แต่ถ้าโจทย์สั่งให้เราหาn100  ละก็ เราคงไม่มีปัญญาหา Close Form ได้ง่ายๆ

2.     เขียน Loop for วนบวกไปเรื่อยๆ วิธีนี้ก็นับว่า ok ครับ เข้าใจง่ายดี แต่มันก็ยังไม่เท่ห์มาก

3.     เขียน Recursive Programming ซะเลย ลองดู Code ข้างล่างนี้ครับ

sigmaN(int n) {

     if (n == 1) return 1;

     else return n + sigmaN(n-1);

}

          จาก Code จะเห็นว่า ถ้ากรณี n = 1 ก็คือค่าไปเลยว่า ได้คำตอบคือ 1 แต่ถ้า n มากกว่า 1 เราก็จะได้ว่า

           n    = n + (n-1)

= n + (n-1) + (n-2)

= n + (n-1) + (n-2) + (n-3)

…..

= n + (n-1) + (n-2) + ….. + 1

 

          เช่นตัวอย่าง5 = 5 + 4

= 5 + 4 + 3

= 5 + 4 + 3 + 2

= 5 + 4 + 3 + 2 + 1

 

          นั่นเอง เห็นมั้ยครับ ว่าวิธีนี้ เข้าใจได้ไม่ยาก นำไปใช้ได้หลากหลาย และ Powerful มาก

 

 

เอาล่ะ ต่อไปได้เวลาลงมือทำงานเพื่อส่งแล้วครับ (ก่อนหน้านี้ ไม่ต้องส่งนะ พวก TestSay, TestShout, TestWhisper เนี่ย) จะเขียนด้วยวิธีใดก็ได้ ที่ตัวเองถนัดและเข้าใจที่สุด ให้ทำงานได้ถูกต้อง ก็เป็นใช้ได้

ทุก Method ที่เขียน ต้องเขียน Test Case อย่างน้อย 5 Case ให้ครอบคลุมช่องโหว่ทุกกรณี โดยแต่ละ Class ให้เขียน Test Case แยกกันมา แล้วให้เขียน Test Suite ชื่อว่า AllTest ซึ่งประกอบด้วย Test Case ของแต่ละ Class อีกที เวลาส่งงานให้ส่ง Test Case และ Test Suite มาด้วยก็แล้วกันนะ

          วิธีการตรวจงาน ผมจะเอา Class ที่สั่งให้เขียน มาทดสอบด้วย Test Suite ของผมเองว่าทำงานถูกต้องตามที่สั่งหรือไม่ ย้ำอีกทีว่าแต่ละข้อคิดให้ครอบคลุมทุกกรณีให้มั่นใจว่าทำงานถูกแน่ๆนะ

 

1. Greatest Common Divisor (GCD) เรียกเป็นไทยว่าหารร่วมมากนั่นเอง

          วิธีที่นิยมใช้กันทั่วไป เวลาเขียนโปรแกรม คือ วิธีการหาแบบ ยูคลิด วิธีการคือ หากเรามีเลข 2 ตัวที่ต้องการจะหา คือ a, b (ให้ a > b ละกัน) เราจะทำเลขที่น้อยกว่าไปหารเลขที่มากกว่า แล้วนำเศษ r ที่ได้มาเก็บไว้ (แน่นอน ว่าเศษที่ได้ต้องน้อยกว่า a, b อยู่แล้ว) จากนั้นก็ดูว่า r1 เป็น 0 หรือไม่ ถ้า r เป็น 0 ก็ตอบได้ทันทีว่า b เป็น GCD แต่ว่าถ้า r1 ไม่เท่ากับ 0 ก็นำ  b, r1 ไปหา GCD ต่อได้  r2 แล้วก็วนทำไปเรื่อยๆจนกว่า r ตัวสุดท้ายเป็น 0

          a   = b   * q1 + r1

          b   = r1 * q2 + r2

          r1 = r2 * q3 + r3

          …….

          rn = r(last)0 * q(last) + 0        ß      ได้ r ตัวสุดท้ายแล้ว นี่ล่ะ คือ GCD

ให้เขียนเป็น Static Class เลย เวลาเรียกใช้ก็เรียกโดยคำสั่ง GCD(a, b) ซึ่ง return ค่าเป็น int นะ

 

2. Least Common Multiple (LCM) เรียกเป็นไทยได้ว่า คูณร่วมน้อยนั่นเอง

          วิธีการหา ก็คล้ายๆ กันกับ GCD นั่นล่ะ ลองนั่งนึกดูสมัยเด็กๆว่าเราหากันยังไง หรือจะใช้ความสัมพันธ์ ระหว่าง a, b, GCD, LCM มาใช้หาก็ได้

          ให้เขียนเป็น Static Class เลย เวลาเรียกใช้ก็เรียกโดยคำสั่ง LCM (a, b) ซึ่ง return ค่าเป็น int นะ

 

3. ให้เขียน Class ชื่อว่า Fraction (แปลเป็นไทยว่าเศษส่วน) โดยใน Class นี้มี Attribute 2 ตัว คือ numerator (เศษ) และ denominator (ส่วน) ต้องทำเลขให้เป็นเศษส่วนอย่างต่ำ เช่น 2/4 ต้องออกมาเป็น 1/2 นะ และ input เป็น จำนวนเต็มบวกเท่านั้น

มี Method คือ

1.1 public double value() ให้คืนค่าออกมาเป็นทศนิยม

1.2 public Fraction add(Fraction f)

1.3 public Fraction subtract(Fraction f)

1.4 public Fraction multiply(Fraction f)

1.5 public Fraction divide(Fraction f) – หากส่วนเป็น 0 ให้ร้องว่า “error – zero by division”

1.6 public Boolean GreaterThan(Fraction f) หาก เศษส่วนตัวที่ต้องการเทียบมากกว่า f ให้ตอบ  true เช่น  t เป็น 2/3 และ f เป็น ½ จะได้ว่า t.GreaterThan(f) = true

1.7 public Boolean Equals(Fraction f) หาก เศษส่วนตัวที่ต้องการเทียบมีค่าเท่ากับ f ให้ตอบ  true

1.8 public String printFraction(Fraction f) – ให้คืน String อยู่ในรูป x/y  ไม่ต้องมีเว้นวรรคนะ เขียนเลข และเครื่องหมาย / ต่อกันมาเลย

 

2. ให้เขียน Class ชื่อว่า Factorial โดยใน Class นี้ มี Attribute 1 ตัวเท่านั้น คือ n (หากได้รับค่าพารามิเตอร์ เป็น 0 หรือ น้อยกว่า 0 ให้ Fail แล้วร้องเลยว่า “error – must be positive number”) นอกจากนี้ ให้ input มีค่าไม่เกิน 1000 ก็พอ ไม่งั้นเดี๋ยวเครื่องจะงอแง

มี Method คือ

          2.1 public int value() – ให้คืนค่า Factorial นี้ เช่น 5! = 120 เป็นต้น

          2.2 public String printFactorial() - ให้คืน String อยู่ในรูป n!

2.3 public Boolean GreaterThan(Fratorial f) หาก เศษส่วนตัวที่ต้องการเทียบมากกว่า f ให้ตอบ  true เช่น  t เป็น 3! และ f เป็น2! จะได้ว่า t.GreaterThan(f) = true

2.4 public Boolean Equals(Fraction f) หากตัวที่ต้องการเทียบมีค่าเท่ากันให้ตอบ  true

          2.5 public String printMultipleForm() -  ให้คืน String อยู่ในรูป

n * n-1 * n-2 …  เช่น 3! = 3 * 2 * 1 เป็นต้น ไม่ต้องมีเว้นวรรคนะ เขียนเลข ดอกจันทร์และอัศเจรีย์ต่อกันมาเลย

 

3. ให้เขียน Class ชื่อว่า Permutation โดยใน Class นี้ มี Attribute 2 ตัว คือ n และ r

(โดยที่ n > r เสมอนะ) และแน่นอน ให้ input มีค่าไม่เกิน 1000 ก็พอ ไม่งั้นเดี๋ยวเครื่องจะงอแง โวยวายและดื้อดึง

          มี Method คือ

3.1  public int value() – ให้คืนค่า P(n, r) ออกมาเป็นจำนวนเต็ม

3.2 public Boolean GreaterThan(Permutation p) หากตัวที่ต้องการเทียบมากกว่า p ให้ตอบ  true เช่น  t เป็น (100,1) และ p เป็น (10,1) จะได้ว่า t.GreaterThan(p) = true

3.3 public Boolean Equals(Permutation p) หากตัวที่ต้องการเทียบมีค่าเท่ากับ p ให้ตอบ  true

          3.4 public String printPermutation() - ให้คืน String อยู่ในรูป  

n! / (n-r)! ไม่ต้องมีเว้นวรรคนะ เขียนทุกอย่างต่อกันมาเลย

 

4.  ให้เขียนคลาสชื่อ Fibonacci โดยคลาสนี้ มี Attribute 1 ตัวเท่านั้น คือ f โดยที่ f มีค่าไม่เกิน 100 ก็พอ

          มี Method คือ

          4.1 public String printFibonacci ()ให้เขียนลำดับ Fibonacci ออกมาเป็น String โดยเลขแต่ละตัว คั่นด้วยเครื่องหมาย , และไม่ต้องมีเว้นวรรคนะ

... เออ ลืมอธิบายไปว่า Fibonacci คืออะไร

          Fibonacci เป็นลำดับแบบนี้ครับ 1, 1, 2, 3, 5, 8, 13, 24 ... สังเกตไหมครับ ว่า ค่าของพจน์ที่ n นั้น จะเกิดจากผลบวกของค่าพจน์ที่ n-1 และ n-2 นั่นเอง

 

5. ให้เขียนคลาสชื่อ PascalTriangle โดยคลาสนี้ มี Attribute 1 ตัวเท่านั้น คือ n มีค่าไม่เกิน 100 ละกัน

          มี Method คือ

          5.1  public String printPascalTriangle ()ให้เขียนสัมประสิทธิ์ของ (x+y)n คืน เป็น String โดยเลขแต่ละตัว คั่วด้วยเครื่องหมาย , และไม่ต้องมีเว้นวรรคนะ เช่น

         

n

สัมประสิทธิ์

1

1,1

2

1,2,1

3

1,3,3,1

4

1,4,6,4,1

 

การส่ง

export ไฟล์เป็น jar file (ต้องมีซอร์สโค้ด ตรวจทานให้ดี) แล้วส่งมาที่ progmethcp@gmail.com ภายในวันเสาร์ที่ 14 กรกฎาคม เวลา 24.00 . ไฟล์จะต้องตั้งชื่อว่า lab06_xxxxxxxxxx.jar โดย xxxxxxxxxx นั้นเป็นเลขประจำตัวนิสิต ส่วนใน subject ของเมล์ ให้ใส่ lab06_xxxxxxxxxx_Time โดย xxxxxxxxxx นั้นเป็นเลขประจำตัวนิสิต และ Time เป็นเวลา (หน่วยเป็นชั่วโมง:นาที) ที่นิสิตใช้ในการทำแล็บนี้