การทดลองที่ 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 เป็นเวลา (หน่วยเป็นชั่วโมง:นาที) ที่นิสิตใช้ในการทำแล็บนี้