avatar
thiti.dev
วงแหวนเว็บ
Search
Tags
My CV
Contact
Support me
Go EP.7 Go Unit Testing
25 Sep 2021

สวัสดีครับ ในบทความนี้ก็เป็น EP.7 แล้วนะครับ โดยเนื้อหาจะเป็นเรื่องเกี่ยวกับ Unit Testing ซึ่งเป็นเรื่องที่มีความสําคัญในการพัฒนาโปรแกรมมากๆครับ

สําหรับท่านใดที่ยังไม่ได้อ่าน EP.6 ท่านสามารถกลับไปอ่านก่อนได้นะครับที่นี่ Go EP.6 Go Channel

มาเริ่มเรียนรู้ไปด้วยกันตามหัวข้อด้านล่างเลยครับ

Unit Test คืออะไร

Unit Test เป็นส่วนหนึ่งในการพัฒนา Software ครับ ไม่ว่าเราจะพัฒนา Software ในภาษาใดๆก็ตาม เราจําเป็นจะต้องเขียน Unit Test เพื่อช่วยในการตรวจสอบการทํางานของโปรแกรมที่เราเขียนขึ้นเพื่อให้แน่ใจว่าการทํางานของโปรแกรมนั้นจะเป็นไปตามที่เราต้องการอย่างแน่นอน และเมื่อเรามาแก้ไข Software ภายหลัง ทําให้แน่ใจได้ว่า สิ่งที่เราแก้ไขนั้นไม่กระทบในส่วนอื่นๆ และยังสามารถทํางานได้อย่างถูกต้อง

ในการเขียน Unit Test นั้นมีกระบวนการเขียนที่เรียกว่า Test Driven Development (TDD) ดังนี้ครับ

Test Driven Development (TDD) จะเริ่มจากเขียน Test case ตาม Requirement ที่เราต้องการก่อน แล้วเมื่อ Run test จะไม่ผ่าน (Test fail) เนื่องจากเรายังไม่ได้ Implement อะไรเลย ขั้นตอนต่อไปให้เรา Implement ตาม Test case ที่ fail เพื่อให้ Test case นั้นผ่าน

เมื่อ Implement จน Test case ผ่านทั้งหมดแล้ว ขั้นตอนต่อไปเราก็จะทําการ Refactor code ให้ Code ของเราออกมาเป็นระเบียบง่ายต่อการมาแก้ไขภายหลังครับ

เริ่มต้นเขียน Unit Test ในภาษา Go

เริ่มแรกเรามาดูตัวอย่าง Requirement กันครับ ดังนี้

  • อะไรก็ตามที่หาร 15 ลงตัว ให้แสดงผลเป็ร FizzBuzz
  • อะไรก็ตามที่หาร 5 ลงตัว ให้แสดงผลเป็น Buzz
  • อะไรก็ตามที่หาร 3 ลงตัว ให้แสดงผลเป็น Fizz
  • ถ้าไม่เข้า 3 เงื่อนไขข้างบนให้แสดงตัวเลข ที่ใส่เข้าไปออกมา

ลําดับความสําคัญจะเรียงตามบรรทัดด้านบนเลยครับ

ขั้นตอนแรกเราสร้าง Project ขึ้นมาก่อนครับ ในที่นี้ผมใช้ชื่อว่า go-fizzbuzz ละกันนะครับ

จากนั้นให้เราสร้างไฟล์ fizzbuzz.go ขึ้นมา โดยภายในจะมี function FizzBuzz ว่างๆ รอไว้ก่อน ดังนี้

package fizzbuzz

func Fizzbuzz(number int) string {
    return ""
}

ขั้นตอนต่อไปเราก็จะมาเขียน Test case กันครับ ซึ่งในการเขียน Unit Test ในภาษา Go นั้นเราสามารถสร้างไฟล์โดยมี File name ที่มีรูปแบบตามนี้ "ชื่อไฟล์ที่เราจะเขียนทดสอบ_test.go" โดยปกติเราจะใช้ชื่อที่เหมือนกันกับไฟล์ที่เราต้องการจะเทส ตัวอย่างในบทความนี้เราก็จะใช้ชื่อ fizzbuzz_test.go และเราจะเอาไว้ที่เดียวกันกับไฟล์ fizzbuzz.go แล้วใส่ code ดังนี้

package fizzbuzz // --> (1)

import (
    "testing" // --> (2)
)

func TestInputDivideBy15ShouldBeDisplayFizzBuzz(t *testing.T) { // --> (3)

    inputList := []int{15, 30, 45, 60, 75, 90}

    for _, n := range inputList {
        v := Fizzbuzz(n)

        if "FizzBuzz" != v {
            t.Error("fizzbuzz of", n, "should be 'FizzBuzz' but have", v)
        }
    }
}

func TestInputDivideBy5ShouldBeDisplayBuzz(t *testing.T) { // --> (4)

    inputList := []int{5, 10, 20, 25, 35, 40, 50}

    for _, n := range inputList {
        v := Fizzbuzz(n)

        if "Buzz" != v {
            t.Error("fizzbuzz of", n, "should be 'Buzz' but have", v)
        }
    }
}

func TestInputDivideBy3ShouldBeDisplayFizz(t *testing.T) { // --> (5)

    inputList := []int{3, 6, 9, 12, 18, 21, 24}

    for _, n := range inputList {
        v := Fizzbuzz(n)

        if "Fizz" != v {
            t.Error("fizzbuzz of", n, "should be 'Fizz' but have", v)
        }
    }
}

func TestInputOtherNumberShouldBeDisplayInputNumber(t *testing.T) { // --> (6)

    inputList := []int{1, 2, 4, 7, 11, 13, 17, 16}

    for _, n := range inputList {
        v := Fizzbuzz(n)

        if fmt.Sprintf("%d", n) != v {
            t.Error("fizzbuzz of", n, "should be '", n, "' but have", v)
        }
    }
}

จาก Code ผมจะอธิบายเป็นข้อๆตามผมายเลขด้านบนดังนี้

  1. เราจะกําหนดให้ Test เป็น package เดียวกันกับ Function ที่เราต้องการจะเทส
  2. Import package "testing" เข้ามา ซึ่ง Package นี้จะมีตัวช่วยสําหรับการเขียน Unit Test ให้เราได้ใช้งาน
  3. เขียน Test case แรกครับ โดยเราจะสร้าง Function ขึ้นมา แล้วรับ Parameter "t *testing.T" เข้ามา ภายใน Function นี้เราจะเขียนเทสตามที่เราต้องการ ในที่นี้ผมสร้าง Input ขึ้นมา 1 ชุด แล้วทําการ Loop เพื่อ check output ตามที่เราคาดหวัง
  4. ทําเหมือนกับข้อ 3 แต่เป็นอีก Test case นึง
  5. ทําเหมือนกับข้อ 3 แต่เป็นอีก Test case นึง
  6. ทําเหมือนกับข้อ 3 แต่เป็นอีก Test case นึง

เมื่อเรารันเทสโดยใช้คําสั่งนี้

$ go test

จะได้ตามรูปด้านล่าง

จะเห็นว่า Test Fail เนื่องจากเรายังไม่ได้ Implement function Fizzbuzz เลย

ขั้นตอนต่อไปเราจะไป Implement function Fizzbuzz เพื่อให้ Test case ของเราผ่าน โดยเราจะ Implement และ Run test ไปเรื่อยๆตาม Test case ที่ fail จนกว่า Test case จะผ่านหมดทุก Test case ครับ

ก็จะได้ function Fizzbuzz ดังนี้ครับ

ackage fizzbuzz

import "fmt"

func Fizzbuzz(number int) string {
    switch 0 {
    case number % 15:
        return "FizzBuzz"
    case number % 5:
        return "Buzz"
    case number % 3:
        return "Fizz"
    default:
        return fmt.Sprintf("%d", number)
    }
}

และเมื่อรัน Test จะได้แบบนี้ครับ

หมายความว่า Function ของเราสามารถทํางานได้ถูกต้องครบถ้วนแล้วครับ

ในการใช้งานจริงจะเห็นว่าถ้าเราเขียน Test case ได้ถูกต้องครบถ้วนมากเท่าไร Software ของเราก็จะทํางานได้อย่าถูกต้องตามที่เราต้องการมากเท่านั้น

โหลด Project ตัวอย่างได้ที่นี่ครับ https://github.com/thiti-y/go-fizzbuzz.git

มาถึงจุดนี้เราก็สามารถเขียน Unit Test ในภาษา Go เบื้องต้นกันแล้วนะครับ จริงๆในการเขียน Unit Test ยังมีเนื้อหาอื่นๆอีกครับ เอาไว้ผมจะมาเล่าให้ฟังอีกทีในบทความต่อๆไปนะครับ

ใน EP.8 จะเป็นเรื่องเกี่ยวกับ Channel Select Multiple Communication Operations ท่านสามารถกดเข้าไปอ่านต่อกันได้ครับ

สําหรับบทความนี้ก็มีเพียงเท่านี้ครับ ขอให้สนุกกับการเขียน Code นะครับ ขอบคุณครับ

thiti.dev © 2021 Thiti Yamsung