feature-image-c#-testing-101
feature-image-c#-testing-101

สรุปเนื้อหาหลักๆ

ไม่ว่าเขียนภาษาอะไรก็ ควรจะใส่ใจเรื่องการเขียนเทส สิ่งที่เราควรรู้กับการเขียนเทสด้วย C# หลักๆก็จะไม่พ้นพวก Libraries หลักๆอย่าง Nunit และ MoQ ซึ่งจริงๆแล้ว Learning Curve ของการเรียนรู้มันตํ่ามากๆเลย โดยมีหลักการณ์ง่ายๆเลย ถ้าเขียน Unit Testing มันยากนัก แสดงว่ามันมีปัญหาเรื่องของ Design ใน code เราแล้วล่ะ 🙂 รวมไปถึงหลักการณ์หลักของการเขียนเทสคือ

the aaa syntax (arrange,act,assert)

การ arrange ค่าต่างๆเพื่อเทส, Act หรือ behavior และ assert ด้วย nunit

ดังนั้นสิ่งที่จะเรียนรู้วันนี้ก็คือเรื่องของการ Nunit พื้นฐาน และ Mock Dependencies และ Verify ออกไปเพื่อทําการเทสนั้นเอง 🙂

C# Testing เริ่มยังไง?

เข้าเนื้อๆเลยจะได้ไม่เสียเวลาคือ ทํา Unit Testing เราจะสนใจ Libraries หลักๆ 2 ตัวก็คือ

  1. Nunit (เหมือน Junit ใน Java มันก็คือเรื่องของการทํา Assertion ต่างๆ เช่น Assert.True/ False/ Equal เป็นต้น)
  2. MoQ (Libary เพื่อใช้ในการ Mock Dependencies และ Verify state ต่างๆของที่เราเขียนเทสนั้นๆ)

จริงๆมี Library อีกหลายตัวที่น่าสนใจที่สามารถใช้ในการ Mock ได้ เพียงแต่เลือกตัวนี้ เพราะคนใช้เยอะเลย

ซึ่งการเขียน Unit Test ก็ไม่ได้ยากไรเลย มันก็เหมือน unit testing ทุกๆภาษานั้นแหละ สิ่งที่เราต้องรู้ก็คือว่าพวก Nunit และ Moq มีอะไรให้เราใช้บ้างแล้วเอามาใช้งาน (แต่โดยหลักๆก็คือสร้าง TestFixture, Test Attribute ExpectedException Attribute, Ignore Attribute พวกนี้ แล้วก็ใช้ MoQ ในการ Mock dependencies แบบนี้แหละ)

Nunit ต้องรู้ไรบ้าง

การใช้ Nunit ง่ายมาก คือ เราแค่ต้องตั้งค่า Attribute ให้กับ Test ของเรา เพื่อให้ Nunit รู้ว่า Method ไหนคืออะไร และเราต้องกาทําไรกับมันบ้าง แล้วก็ Assert เพื่อเช็คค่ามันว่าทํางานถูกหรือไม่แค่นั้นเลย

โดยเราสามารถดู Attribute ทั้งหมดได้จาก Wiki ของมันเลย

แต่จริงๆแล้วมันก็มีแค่ที่เราใช้บ่อยๆคือ [TestFixture] = บอกว่า class นี้มีเพื่อทํา test,[Setup] = เพื่อตั้งค่าพวก config ต่างๆของ test อาจจะเป็นพวก setup MoQ แบบนั้น, [Test] = บอกว่านี้คือ Method ที่จะให้ทํา test

Nunit-sample-asserttest
Nunit-sample-asserttest (https://github.com/nunit/nunit-csharp-samples/blob/master/syntax/AssertSyntaxTests.cs#L27)

เจ้าตัวนี้เป็นตัวอย่างที่น่าสนใจที่เดียวเลย เพราะมันเป็นการเขียน Test Nunit Syntax ของมันเอง โดยจากที่เราเห็นในรูปจะมี comment ถึง 3 อย่างคือ classic, constraint และ inherited syntax นั้นคือรูปแบบของการเขียน Assert model แบบต่างๆ

ถ้าใครเคยใช้ Nunit มาอยู่แล้วจะคุ้นเคยแบบ Assert มาก เพราะมันก็คือแบบ Assert.IsNull(x), Assert.IsNotNull(x) เป็นต้น (ดูรวม classic model ของ Nunit ได้ ที่นี้) แต่สําหรับการใช้ constraint sytanx มันจะเป็นการย่อและเอาพวก logic ที่จําเป็นอยู่ในนั้นเลย (ดูรวมๆ constraint model ได้ ที่นี้)

MoQ ต้องรู้อะไรบ้าง

MoQ = friendly mocking framework for .NET เจ้าตัวฮิตตัวนี้เกิดมาเพื่อทําหน้าที่ Mockๆ เท่านั้นเลย ซึ่งสิ่งที่มันสามารถทําได้ก็คือ Mock Interfaces และ Classes ต่างๆ เพื่อตัด dependencies ออกไป (Mock คืออะไร อ่านเรื่องของ TestDouble ได้ที่นี้) วิธีลงก็ลงผ่าน NuGet

สิ่งที่สังเกตุเห็นชัดๆเลยก็คือมันก็เหมือน Mock Framework ทุกอันแหละ คือ

  1. การสร้าง MockObject
  2. แล้วโยนไปแทนที่ Object จริงเพื่อจัดการให้มันทํางานแทน
  3. verfiy มันแบบนั้น

แต่เจ้านี้เสียอย่างเดียวคือเรื่องของ Document กับ Tutorial น้อยมากกกกสิ่งที่เค้า Provide ให้ก็จะมีแค่ Quickstart guide กับ NuDoc ซึ่งจริงๆมันก็พอแหละ แค่ต้องลองเข้าไปเล่นเอาเอง 🙂 แต่สําหรับคนใหม่ๆกว่าจะแยกพวกนี้ออกเป็นส่วนๆได้คงใช้เวลาหน่อย (ถ้าอยากรู้ว่ามีไรใน MoQ ให้ใช้บ้าง แนะนําเปิด NuDoc ไว้เสมอน่ะ)

ที่นี้มาดูตัวอย่างของการใช้ของ MoQ เอง ด้วยตัว samples ของมันกัน โดยจะเริ่มจากการเขียน Unit Testing Application ของ StoreSample โดยมันจะมุ่งไปที่ ProductsPresenter Class ที่ทําหน้าที่ควบคุมการเลือกสินค้า ส่วน Unit Testing จะชื่อ ProductsPresenterFixturecs

ProductsPresenter

moq-sample-ProductsPresenter
moq-sample-ProductsPresenter (https://github.com/moq/moq4/blob/master/Samples/StoreSample/Source/Presenters/ProductsPresenter.cs)

ProductsPresenterFixturecs

moq-sample-ProductsPresenterFixturecs
moq-sample-ProductsPresenterFixturecs (https://github.com/moq/moq4/blob/master/Samples/StoreSample/UnitTests/ProductsPresenterFixturecs.cs#L12)

เจ้า MoQ ก็ไม่แตกต่างกัน ดูได้จากการเขียน Test ของ ShouldSetViewCatrgories() ได้ จะเห็นว่าเปิดมา เราใช้หลักการ AAA (Arrange-Act-Assert) โดย set ค่าของ Mock Object ก่อนเลย ด้วย new Mock<T> เพื่อให้ได้มาซึ่ง Mock Object ออกมา หลังจากนั้นตอนที่เรา Act เราก็โยน mock object เข้าไปด้วย Mock.Object เพื่อให้ AUT เอาไปใช้งานได้

ทีนี้มาดูตอน Verify กันดีกว่า

moq-verify-method
moq-verify-method

จะเห็นว่าบรรทัดที่ 22 มันจะทําการ verify ว่า method SetCatrgories ถูกเรียก ซึ่งถ้าไม่มี object ของ catalog.object ที่เราโยนเข้าไปตอนแรก มันจะทํางานไม่ได้นั้นเอง

moq-sample-class
moq-sample-class

ถึงจังหวะนี้ทุกคนคงเข้าใจคร่าวๆว่ามันทําอะไร แต่ที่น่าจะเริ่มฉุกใจและงงขึ้นมาบ้างแล้วคือ บรรทัดที่ 22 มันเขียนบ้าอะไร 🙂 อ่านแล้วไม่เข้าใจ ดังนั้นลองมาดู API กัน

moq-verify-document
moq-verify-document (http://www.nudoq.org/#!/Packages/Moq/Moq/Mock(T)/M/Verify)

เจ้าตัวนี้มันคือสิ่งที่เรียกว่า LINQ (Lambda Expression) นั้นเอง!!! 🙂

LINQ คืออะไร?

LINQ (Language Integrated Query) มันคือ query synatx แบบนึงที่ใช้ในการ save/retrieve ข้อมูลจาก data sources.

what-is-linq
what-is-linq (http://www.tutorialsteacher.com/linq/what-is-linq)

จากรูปจะเห็นว่าเราสามารถใช้ LINQ ในการ Query data source ได้หลากหลายแบบเลยล่ะ เนี่ยเป็นจุดเด่นของ LINQ เลยน่ะ เพราะลองคิดดูว่าถ้าเราต้องเขียน Query สําหรับ XML,SQL หรือ object เองในหลายๆวิธีการ มันจะทําให้เราเสียเวลามากมายขนาดไหน? ทั้งเรื่องของการ Maintain และ Skills set อีก …. นี้เลยเป็นจุดกําเหนิด LINQ นั้นเอง

ทีนี้มันมาเกี่ยวข้องอะไรกับ MoQ ล่ะ? อย่างที่เรารู้กันว่า LINQ Expression ถูก Implement ไว้ใน API ดังนั้นเราจะต้องใช้ LINQ ในการ Query Object ที่เราทําการ Mock เอาไว้นั้นเอง โดยถ้าเราไปดู บรรทัดที่ 22 จะพบว่านั้นคือ syntax ของสิ่งที่เรียกว่า Lambda Expression 

moq-verify-method
moq-verify-method

เริ่มไปหลายเรื่องล่ะ แต่การใช้ MoQ เราจําเป็นต้อนรู้เรื่องพวกนี้น่ะ 🙂

การใช้ Lambda Expression เพื่อ Query Object ต่างๆช่วยให้เราเขียนโค้ดน้อยลงมาก ซึ่งหลักการง่ายๆของมันก็คือการลดรูปของ delegate 

delegate แบบสั้นๆ

ขออธิบาย delegate สั้นๆง่ายๆน่าจะเรียกได้ว่า delegate base type เนี่ยมันมีความสามารถในการทํางานโดยไม่สนใจ type ของอะไรทั้งนั้น ขอให้มี แค่ signature เหมือนกัน ก็สามารถทํางานได้แล้ว

delegate-c#-example
delegate-c#-example (https://msdn.microsoft.com/en-us/library/900fyy8e(v=vs.71).aspx)

ทีนี้เจ้า Lambda Expression เนี่ยมันก็มันจะ shorter way ในการจัดการกับ anonymous method (delegate นั้นแหละ) ซึ่งผลลัพธ์ก็จะออกมาหน้าตาอย่างนี้

lambda-expression-for-anonymous-method-example
lambda-expression-for-anonymous-method-example (http://www.tutorialsteacher.com/linq/linq-lambda-expression)

ซึ่งจากตัวอย่างข้างบนแปลว่า รับตัวแปร (Arguments) Student S เข้าไป แล้วให้ return true-false ออกไปถ้า Student มีอายุอยู่ในช่วง 12-20 นั้นเอง

น่ารู้กับ Lambda คือ

point-to-remember-lambda-expression
point-to-remember-lambda-expression (http://www.tutorialsteacher.com/linq/linq-lambda-expression)

ทบทวนแนวคิดก่อนไปต่อ

การเขียน Unit Testing ง่ายมาก แค่

  1. ใช้แนวคิด AAA (Arrange-Act-Assert) เพื่อในการ Manage test ของเราแบ่งส่วนชัดเจน
  2. มองหา Object ที่เป็นจุดที่ถูกเรียกไปยังที่อื่นๆ หรือ dependencies ของ code เราเพื่อทําการ Mock
  3. โยน Object เข้าไปให้มันใช้แทน
  4. Verify มัน

จริงๆมันก็มีแค่นี้น่ะ ในการเขียน unit testing อะไรก็ตาม 🙂

สรุปแล้ว

Nunit และ MoQ ช่วยให้ชีวิตง่ายมากในการเขียน Unit Test แล้วจะ Mock Interface หรือ classes ใดๆ แต่เรายังต้องรู้ว่า MoQ ไม่สามาร Mock Static Class/Method ได้ (จริงๆต้องใช้ทริคหน่อยคือ คือเราต้องสร้าง Wrapper แล้วไป Mock method นั้นอีกทีแหละ)

pattern-for-mock-static-class
pattern-for-mock-static-class

แต่ถ้าไม่ทําสไตล์นี้เห็นว่า Typemock ช่วยท่านได้ฮ่าๆ แต่ยังไม่เคยลองน่ะ แต่รู้สึกจะเสียเงินเลยจบข่าว 🙂

เอาเป็นว่าถ้าจะเริ่มเขียน Unit Testing ด้วย C# แนะนําลองเล่น Nunit และ MoQ ก่อนตามตัวอย่างและ ref. ที่แปะไว้ในเว็ปแล้ว จะช่วยให้เห็นภาพกับไล่ลําดับง่ายขึ้นมากๆๆ กับดู Quickstart ของ MoQ เป็นหลักเลยยน่ะ

 

0 0 vote
Article Rating
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments