in Technology

มาลอง Code Coverage บน .Net Core 2+ ด้วย coverlet

ใครที่เขียนโค้ดด้วย .Net Core 2+ และทำ CI/CD บน Linux ค่อนข้างยุ่งยากหน่อย เพราะหาเครื่องมือสำหรับตรวจสอบ Code Coverage ฟรีๆ ดีๆ ได้น้อยเหลือเกิน ที่ผมเคยใช้ดีๆ ก็มี minicover จนเพิ่งมาลองเล่นอีกตัว ชื่อ coverlet ใช้งานได้ง่ายกว่าเยอะมาก เพราะมันทำงานร่วมกับ MSTest ได้เลย

วิธีติดตั้ง

การใช้งานมี 2 แบบครับ คือใช้คำสั่ง coverlet ทำงานเลย ให้ติดตั้งด้วยคำสั่ง

dotnet tool install --global coverlet.console

หรือทำงานผ่านคำสั่ง dotnet test ให้เพิ่ม nuget package ด้วยคำสั่ง

dotnet add package coverlet.msbuild

วิธีใช้งาน

ในตัวอย่างนี้ โครงสร้างโปรเจ็คผมจะหน้าตาตามรูปภาพด้านล่าง และผมเข้าจะยกตัวอย่างคำสั่งทั้งหมดกรณีที่อยู่ในโฟลเดอร์ /tests/web.UnitTest/

ดังนั้น เมื่อต้องการดู Code Coverage ผ่านคำสั่ง coverlet

coverlet bin/Debug/netcoreapp2.1/api.dll --target "dotnet" --targetargs "test web.UnitTest.csproj --no-build" --output "../web.UnitTest.Results/Coverage.xml" --format opencover

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

  • bin/Debug/netcoreapp2.1/api.dll : คือ ที่อยู่ของไฟล์ Unit Test Binary ที่เรา Build มาแล้ว
  • test web.UnitTest.csproj –no-build : คือ arguments เพื่อบอกว่าเราต้องการทดสอบด้วย MSTest ไปที่ File Project ไหน, และผมเพิ่มไปว่า ไม่ต้อง ทำการ build project ใหม่ เพราะผมสั่ง build ไปแล้ว (ถ้าใครไม่สั่ง build ก่อน ให้เอา –no-build ออกด้วยนะ)
  • ../web.UnitTest.Results/Coverage.xml : คือ ที่อยู่ของไฟล์ report ซึ่งผมให้ใช้เป็น Formet ของ OpenCover จึงจ้องมีนามสกุล .xml (ค่ามาตรฐาน ถ้าไม่ระบุ มันจะเป็น JSON)
  • opencover : คือ Format ของไฟล์ report ที่เราจะนำไปใช้งานต่อ

ลองมาดูการใช้งานผ่านคำสั่ง dotnet test แบบปกติบ้าง

dotnet test --no-restore --no-build --logger:"trx;LogFileName=Results.trx" --results-directory:"../web.UnitTest.Results" /p:CollectCoverage=true /p:CoverletOutput="../web.UnitTest.Results/Coverage.xml" /p:CoverletOutputFormat=opencover

ถ้าให้เดาค่าต่างๆ คงพอเดากันได้นะครับ ระบุเหมือนด้านบนเลย แต่คำสั่งหนึ่งที่ต้องมีเสมอคือ

/p:CollectCoverage=true 

เพื่อบ่งบอกว่า เราต้องการ Generate Code Coverage ออกมาด้วย

การแสดงผล

เมื่อรันคำสั่งตามด้านบนเรียบร้อยแล้ว จะได้หน้าตาประมาณนี้ครับ

ความหมายที่ได้จากการแสดงผล คือ

  • Module : ชื่อ System ที่มันทำการทดสอบ
  • Method coverage : จำนวนของ Function/Method ที่ถูกเรียกใช้งาน
  • Branch coverage : จำนวนของ Branch หรือเงื่อนไขใน if statement ถูกเรียกใช้งานทั้ง true และ false
  • Line coverage : จำนวนของบรรทัดที่ถูกเรียกใช้งาน
อ้างอิงคำอธิบายจาก http://www.somkiat.cc/introduction-to-code-coverage/

กำหนดคุณภาพ ด้วยการตั้ง Threshold

คราวนี้ ถ้าเราอยากตั้งค่าว่า ถ้า Code Coverage เรามี Test ครอบคลุมต่ำกว่า xx% เราจะไม่ให้ผ่านการทดสอบ โดยเพิ่ม Argument ชื่อ threshold ลงไป ดังนี้

ตัวอย่างด้วยคำสั่ง coverlet

coverlet bin/Debug/netcoreapp2.1/api.dll --target "dotnet" --targetargs "test web.UnitTest.csproj --no-build" --output "../web.UnitTest.Results/Coverage.json" --threshold 80

ตัวอย่างด้วยคำสั่ง dotnet test

dotnet test --no-restore --no-build --logger:"trx;LogFileName=Results.trx" --results-directory:"../web.UnitTest.Results" /p:CollectCoverage=true /p:CoverletOutput="../web.UnitTest.Results/Coverage.xml" /p:CoverletOutputFormat=opencover /p:Threshold=80 /

ซึ่งในตัวอย่างผมกำหนดว่า Coverage ทุกประเภทจะต้องเกิน 80% ถึงจะเรียกว่าผ่าน ถ้าต่ำกว่านั้นจะ Fail ทันที ดังรูปด้านล่าง

และเราสามารถกำหนดเฉพาะ Coverage ได้ด้วย เช่นผมต้องการเช็คเฉพาะ Line Coverage ก็สามารถเพิ่ม Argument เข้าไป ดังนี้

ตัวอย่างด้วยคำสั่ง coverlet

--threshold-type line

ตัวอย่างด้วยคำสั่ง dotnet test

 /p:ThresholdType=line

ผลที่ได้คือ

สรุป

ถ้าเทียบกับ minicover แล้ว ตัวนี้ค่อนข้างใช้งานง่าย ไม่ซับซ้อนมากนัก รองรับ .Net Core 2.2.1 ตัวล่าสุดด้วย และสามารถแจกแจงรายละเอียด ตาม Coverage Type ต่างๆ พร้อมออก Report ได้ เช่น json, lcov, opencover (xml file), cobertura (xml file) และ teamcity ถ้าสนในรายละเอียดมากกว่านี้ ไปดูได้ที่ Github ของผู้พัฒนาได้เลยครับ ที่ https://github.com/tonerdo/coverlet

Featured image from: https://www.aapnainfotech.com/test-coverage-much-testing-enough/