แนวคิดและวิธีการแยก Test case สำหรับ Test ระบบ Application

Mr.Rukpong
Arcadia Software Development
3 min readJan 3, 2019

Tester ผู้กุมชะตากรรมของ Developer และ Application

การจะเป็น Specialist ในด้านการ Test เราต้องรู้การทำงานของระบบ Application และ Flow การทำงานให้ครบถ้วนอย่างถูกต้อง

☆ ถ้าจะอธิบายการแยก Test case เป็นรูปธรรมต้องเปรียบถึงรากของต้นไม้

  • รากแก้ว เปรียบเหมือน Functional
  • รากฝอย เปรียบเหมือน Non-Functional

สามารถเข้าใจได้ตามที่ยกตัวอย่างมาเลย คือถ้า Flow ของ Functional ขาดไป ก็ทำให้ระบบ Application ล่มได้ ส่วน Non-Functional จะเปรียบเหมือน ส่วนเสริมเพิ่มเติมทำให้ Application เป็น Application ที่ดีได้

เริ่มต้นที่การอธิบายระดับของการ Test มี 3 ระดับหลักๆ คือ

  1. Unit Test — จะเป็นหน่วยย่อยที่สุดของการ test ซึ่งจะ test โดยการ mock data ผ่าน Function นั้นๆ โดยตรง (ส่วนใหญ่ test ระดับนี้จะเป็นส่วนของ Developer)
  2. Integration Test จะเป็นส่วนที่รวบรวม Function ย่อยๆ แต่ละตัวมาเรียงต่อกัน บวกกับ data ที่ผ่านเข้ามาในระบบเส้นสายนี้ (ยังคงเป็นส่วนที่ Developer มีหน้าที่ test โดยการที่นำ data มาผ่าน Function แต่ละ Function แบบเสมือนจริง แต่บางครั้ง Tester ก็ลงมา test ถึงระดับนี้ได้เหมือนกัน)
  3. System Test — จะเป็นการ test แบบ End-to-End คือการ test ตั้งแต่ต้นจนจบกล่าวคือเป็นการ test เทียบเท่ากับการที่ User ใช้งานจริง (การ test ส่วนนี้ เป็นงานหลักของ Tester และ QA เลยครับ)

เมื่อเราพอจะเข้าใจระดับของการ Test แล้ว ทีนี้เรามาเริ่มมาจัด Level ความละเอียดของ Flow กันดีกว่าครับ

  1. Black box ตามชื่อก็คือกล่องดำ หมายถึงการ Test โดยไม่ได้รู้จนถึงการทำงานภายใน Function นั้นๆ แต่ยังสามารถ Validate ข้อมูล Input / Output ที่ผ่าน Function นี้ได้
  2. White box เสมือนกล่องใส ที่เห็นการทำงานตลอดทั้งสาย สามารถ Trace data และเห็น Flow การทำงานได้ ตั้งแต่ data Input, การเปลี่ยนแปลง data ระหว่างที่อยู่ใน Function นั้น และ data Output

จากที่เกริ่นมาข้างต้น เป็นความรู้พื้นฐานให้เข้าใจชนิดของ data และ scenario ที่จะเกิดขึ้น ต่อไปเรามาเริ่มลงรายละเอียดของ Test case เพื่ออธิบาย Concept การแยก Test case ไปทีละหัวข้อเลยครับ

» Functional

การหา Functional เริ่มจากการมอง Flow ของ Application ให้ชัดเจน และรู้การทำงานของ Application ตามลำดับการทำงานก่อนหลังอย่างถูกต้อง

เมื่อเรารู้จัก Function ทั้งระบบของ Application แล้ว จับมาเรียงเป็นลำดับการทำงานของแต่ละ Path ที่เกิดขึ้นได้ เช่น

FunctionA
FunctionB
FunctionC
FunctionD

มี Function ที่เราสนใจใน Feature นั้นๆ 4 ตัว

  • ให้มองหา Path ที่เริ่มต้นตั้งแต่ Input จนกระทั่งถึง Result และนำมาเรียงต่อกัน ตาม Flow ที่เป็นไปได้ เช่น
Testcase1:Input -> FunctionA_FunctionB -> Result
Testcase2:Input -> FunctionA_FunctionC -> Result
Testcase3:Input -> FunctionD_FunctionB_FunctionC -> Result
Testcase4:Input -> FunctionD_FunctionA_FunctionB_FunctionC -> Result

ยกตัวอย่างว่า Application นี้มี Path ที่เกิดขึ้นได้ใน Feature นี้ 4 แบบ เราสามารถสร้าง Test case ของ Functional ได้ 4 แบบ

  • เมื่อเกิด event (input) หนึ่งเกิดขึ้น และเราคาดหวัง (expect result) ให้ผลลัพธ์ออกมาให้ถูกต้อง เท่านี้ก็เตรียม Test case สำหรับ Functional ของ Feature หนึ่งได้แล้วครับ

» Non-Functional

สิ่งสำคัญของการคิด Test case สำหรับ Non-Functional คือ ความน่าจะเป็น

  • list Input ที่สามารถเกิดขึ้นได้ทั้งหมด
  • จัดประเภท data input ประเภท valid และ invalid
  • มี expect ของ case pass และ expect ของ case fail

จากนี้เป็นแค่การจับกรณีที่สามารถเกิดขึ้นได้ทั้งหมด มารวมกันเท่านั้นครับ

จากตัวอย่าง Function 4 ตัวที่กล่าวไว้คือ

FunctionA
FunctionB
FunctionC
FunctionD

เริ่มต้นตาม Concept ความเป็นไปได้ที่น่าจะเกิดขึ้นเลยครับ

  1. Input ที่สามารถเกิดขึ้นได้ทั้งหมด (สมมติให้กรณีนี้สามารถเป็น Int และ String)
  2. แยกประเภท
  • Int เป็นประเภท valid
  • String เป็นประเภท invalid

3. expect สำหรับ case pass (เมื่อ data เป็นประเภท valid) และ expect สำหรับ case fail (เมื่อ data เป็นประเภท invalid)

จากขั้นตอนทั้งหมดจะได ้Test case ทั้งหมดคร่าวๆ ดังนี้

Testcase1: Int -> FunctionA -> Result
Testcase2: String -> FunctionA -> Fail Result
Testcase3: Int -> FunctionB -> Result
Testcase4: String -> FunctionB -> Fail Result
Testcase5: Int -> FunctionC -> Result
Testcase6: String -> FunctionC -> Fail Result
Testcase7: Int -> FunctionD -> Result
Testcase8: String -> FunctionD -> Fail Result
.
.
.
TestCase..: Int -> FunctionA_FunctionB -> Result
TestCase..: String -> FunctionA_FunctionB -> Fail Result

และยังสามารถมีได้อีก อย่างที่กล่าวไปข้างต้น ว่า Non-Functional จะเหมือนรากฝอยของต้นไม้ แยกไปได้หลายรูปแบบ ได้หลากหลายทาง ใจความสำคัญของการแยก Test case ประเภท Non-Functional คือ “ความสมเหตุสมผล” ครับ

การเป็น Tester ที่ดีคือการมองให้ออกว่า Test case ที่กำลังสร้างขึ้น สามารถเกิดขึ้นได้จริงหรือไม่ เพื่อเราจะไม่ต้อง Test ในกรณีที่ไม่มีวันเกิดขึ้นจริง (สามารถลดจำนวน Test case ลงได้อีกด้วย)

** Trick เล็กๆ น้อยๆ ที่ควรรู้

  • การจะ Test เพื่อหาผลลัพธ์ที่เหมือนเดิม ต้องใช้ Input -> Function เหมือนเดิม เมื่อเรา Test ด้วย Input ใหม่ หรือ Function ใหม่ อาจจะทำให้ผลลัพท์เปลี่ยนไปได้
New_Input -> Function     -> ?
Input -> New_Function -> ?
New_Input -> New_Function -> ?
  • Test ด้วย input ที่คล้ายๆ กัน เราจะหยิบข้อมูล ช่วงขอบบน และขอบล่างมา Test เพื่อลดจำนวน Test case ที่คาดว่าจะได้ผลลัพธ์เหมือนกันได้
เช่น มีช่องที่ต้องให้กรอกอายุได้ไม่เกิน 100
Input ที่เราสามารถหยิบมา test เราสามารถใช้
-1 (invalid)
0 (invalid)
1 (valid)
99 (valid)
100 (valid)
101 (invalid)
* ช่วง 1-100 เป็นช่วงข้อมูล valid ซึ่งคาดว่า เป็น input data ที่ถูกต้องแน่นอน

การแยก Test case Functional และ Non-Functional อาศัยประสบการณ์อยู่มาก ต้องเจอรูปแบบการทำงานของ Application หลายๆ กรณี และต้องมองหา Path การทำงานหลัก ที่สามารถเกิดขึ้นได้ จากการเข้าใจ Flow การทำงานของระบบ

เริ่มต้นขั้นพื้นฐานของการ Test อาจจะเริ่มจากการมอง Flow เป็นระบบแบบ Block box และพยายามหา Path การทำงานหลัก ที่สามารถเกิดขึ้นได้ จนคล่องให้ได้ จะเริ่มเห็นความน่าจะเป็นอื่นๆ ได้มากขึ้นครับ

--

--