เคล็ดลับ Go Unit Testing Performance & How to Debug

Jirawan.C
KBTG Life
Published in
4 min readNov 11, 2021

วันนี้เราจะมาเรียนการเขียนโค้ดแบบง่าย ๆ ด้วย Golang และใช้ Go Testing Package ในการเขียน Unit Test เพื่อวัดประสิทธิภาพการทำงานของโค้ดของเรา พร้อมกับแสดงวิธีการ Debug เวลาที่โปรแกรมเกิดปัญหาโดยใช้ Visual Studio Code

มาเริ่มต้นด้วยการสร้างโปรแกรมกัน

ในบทความนี้เราจะมาเขียนโปรแกรมคำนวณเพื่อหาว่าเลขที่เราใส่ไปเป็นจำนวนเฉพาะ (Prime Number = เลขจำนวนเต็มที่ไม่สามารถหารด้วยตัวเลขอื่นได้นอกจากเลข 1 และตัวมันเอง) หรือไม่ โดย Input จะเป็นเลขจำนวนเต็ม 1 จำนวน ถ้าจำนวนดังกล่าวเป็นจำนวนเฉพาะจริง Output จะ Return True แต่ถ้าไม่ใช่จะ Return False

Step 1: สร้าง Work Directory

ใช้คำสั่ง mkdir ในการสร้าง Directory ชื่อ isPrime

$ mkdir ./isPrime

Step 2: สร้างไฟล์

เลือก Work Directory ที่เราสร้างไว้ในขั้นตอนที่ 1 และกดสร้างไฟล์ โดยตั้งชื่อไฟล์ว่า isPrime.go

Step 3: เพิ่มโค้ด

ภายในไฟล์จะประกอบไปด้วย Source Code ดังนี้

(1) Method isPrime รับ Parameter 1 ตัว คือ x ที่มี Type ของข้อมูลเป็น Int และจะคำนวณหาว่า x เป็นจำนวนเฉพาะหรือไม่ ถ้าใช่จะ Return True ถ้าไม่ใช่ Return False

(2) Method Main จะทำหน้าที่เรียก Method isPrime โดยส่งจำนวนเต็มเข้าไป ในตัวอย่างนี้คือ 13 และจะปริ้นท์ผลลัพธ์ออกมาว่าเป็น True หรือ False

Step 4: Go Mod Init & Go Mod Tidy

สร้าง Go Mod File เพื่อเก็บ Dependencies

$ go mod init tipsTest// then go mod tidy to add module requirements and sums$ go mod tidy

Step 5: สั่งรัน

ลองสั่งรันด้วยคำสั่งด้านล่างนี้

$ go run isPrime.go

จะได้ผลลัพธ์ตามภาพ

Return True เพราะ 13 เป็นจำนวนเฉพาะจริง ๆ

เขียน Unit Testing

Unit Testing คือการเขียนโปรแกรมเพื่อทดสอบการทำงานในแต่ละ Module ให้เรามั่นใจว่าโปรแกรมสามารถทำงานได้อย่างถูกต้อง

Step 1: สร้าง Test File

ชื่อไฟล์จะต้องลงท้ายด้วยคำว่า _test.go เช่น isPrime_test.go

Step 2: สร้าง Function

สร้าง Function สำหรับเขียน Test โดยตั้งชื่อตามฟอร์แมต func TestXxxx(t *testing.T)

  • ชื่อ Function ต้องขึ้นต้นด้วยคำว่า Test
  • ตามด้วยตัวอักษรตัวแรกของคำเป็นตัวพิมพ์ใหญ่
  • Function จะรับ Input แค่ t *testing.T
func TestIsPrime(t *testing.T)  {
//body
}

Step 3: เพิ่มโค้ดเพื่อเรียกใช้งาน isPrime Function

TestIsPrime Function จะเรียก isPrime Function ที่เราประกาศไว้ก่อนหน้านี้ใน Package Main

Step 4: Run the Test

ลองสั่งรันด้วยคำสั่ง

$ go test

จะได้ผลลัพธ์ตามภาพ

// output
PASS
ok tipsTest 0.404s

หรือกด run test จะได้ผลลัพธ์ออกมาเป็น Ok

PASS หมายถึงโค้ดสามารถทำงานได้ถูกต้องตามที่คาดหวังไว้ แต่ถ้าเทสแล้วไม่ผ่านจะแสดงผลลัพธ์ FAIL

ถ้าอยากเห็นว่าแต่ละเทสที่รันใช้เวลาเท่าไหร่ ให้เพิ่ม Flag -v เข้าไป

$ go test -v

จะได้ผลลัพธ์ตามภาพ

// output
=== RUN TestIsPrime
--- PASS: TestIsPrime (0.00s)
PASS
ok tipsTest 0.134s

เริ่มเขียน Benchmarks

ทีนี้มาถึงการทำ Benchmark เพื่อวัดประสิทธิภาพการทำงานของโค้ดที่เขียนขึ้นมาว่า Performance เป็นอย่างไร

Step 1: สร้าง Benchmark Function

ตั้งชื่อ func BenchmarkXxx(*testing.B)

  • ชื่อของ Function ต้องขึ้นต้นด้วยคำว่า Benchmark
  • คำที่ตามหลังตัวอักษรตัวแรกของคำต้องเป็นตัวพิมพ์ใหญ่
  • รับ Input (*testing.B)
func BenchmarkIsPrime(b *testing.B) {
for i := 0; i < b.N; i++ {
isPrime(9897)
}
}

Step 2: รัน Benchmark

$ go test -bench=.// output
goos: darwin
goarch: amd64
pkg: tipsTest
cpu: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz
BenchmarkIsPrime-8 192724854 6.221 ns/op
PASS
ok tipsTest 2.233s

ผลลัพธ์จะแสดงให้เห็นว่าลูปไปทั้งสิ้น 192,724,854 ครั้ง และใช้เวลา 6.221 Nanosecond ต่อลูป

. จะรันทุก ๆ Benchmark Function ในไฟล์

Step 3: วัด Performance

เพิ่มประสิทธิภาพด้วยการทดลองเขียนวิธีการคำนวณจำนวนเฉพาะด้วยวิธีอื่น โดยสร้างไฟล์ใหม่ชื่อ isPrime2.go และสร้าง Function isPrime2

จากนั้นเพิ่มโค้ดใน IsPrimeBenchmark_test.go ดังรูป

ลองรัน Test อีกครั้งจะได้ผลลัพธ์ตามนี้

$ go test -bench=.//output
goos: darwin
goarch: amd64
pkg: tipsTest
cpu: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz
BenchmarkIsPrime-8 193049048 6.229 ns/op 0 B/op 0 allocs/op
BenchmarkIsPrime2-8 193192003 6.223 ns/op 0 B/op 0 allocs/op
PASS
ok tipsTest 3.781s

จะเห็นว่าผลลัพธ์ของ BenchmarkIsPrime2 เทียบกับ BenchmarkIsPrime นั้นใช้เวลาต่างกัน โดย BenchmarkIsPrime2 ใช้เวลา 6.223 ns/op ในขณะที่ BenchmarkIsPrime ใช้เวลา 6.229 ns/op

เพียงเท่านี้เราก็สามารถทำการวัดประสิทธิภาพของโค้ดที่เราพัฒนาขึ้นมาได้ว่าเป็นตามที่เราต้องการหรือไม่

เริ่ม Debug โค้ดโดยใช้ Visual Studio Code

เราจะใช้ Breakpoints ในการ Debug Error ซึ่งการ Debug จะแสดงค่าของ Variable ในแต่ละ State ที่โค้ดถูกรัน

Step 1: ติดตั้ง dlv-dap

รันคำสั่งด้านล่างเพื่อติดตั้ง

$ brew install go-delve/delve/delve

Step 2: Debugging With Breakpoints

คลิกด้านหน้าเลขบรรทัดของโค้ดเพื่อเพิ่ม Breakpoints ในกรณีนี้เราจะใส่ Breakpoints ที่บรรทัดที่ 14 ก่อนเข้า For Loop

Step 3: เริ่ม Debug Test

เลือก Debug Test เพื่อรัน

เมื่อรันมาถึงบรรทัดที่ 14 เจอ Breakpoints โปรแกรมจะหยุด Pause ตรงนี้ ให้สังเกต Panel ด้านซ้ายมือ (กรอบสีเหลือง) จะเห็นค่าตัวแปรและ State ต่าง ๆ เราสามารถกด Forward ในกรอบสีแดงให้รันโปรแกรมบรรทัดถัดไปเพื่อ Debug ต่อ หรือกดไอคอนด้านซ้ายของกรอบสีแดงเพื่อรันต่อไปเรื่อย ๆ จนไปหยุดที่ Breakpoints

หากต้องการดูตัวอย่างโค้ด สามารถเข้าไปดูที่ GitHub ด้านล่างนี้ได้เลยค่ะ

หวังว่าบทความนี้จะเป็นประโยชน์ต่อผู้พัฒนาที่อยากลองเริ่มเขียน Unit Testing และวัดประสิทธิภาพโปรแกรมที่เราเขียน หากคุณชอบบทความของเรา รบกวนกด “Claps” 👏 เพื่อเป็นกำลังใจให้เราเขียนบทความต่อไปด้วยนะคะ ขอบคุณค่ะ

References

สำหรับชาวเทคคนไหนที่สนใจเรื่องราวดีๆแบบนี้ หรืออยากเรียนรู้เกี่ยวกับ Product ใหม่ๆ ของ KBTG สามารถติดตามรายละเอียดกันได้ที่เว็บไซต์ www.kbtg.tech

--

--

Jirawan.C
KBTG Life

Hi, My name's JUGJIG. I working as a software engineer @Fintech company. I’m Go developer since 2020. I’m English learner. Nice to see you