Test Double

วันนี้ได้อ่านบทความที่เกี่ยวกับการทำ test และได้รู้คำใหม่ๆ เช่น Test Double ที่ใช้เรียก class ที่ใช้ในการกันส่วนที่ไม่เกี่ยวข้องกับส่วนที่ต้องการทดสอบออกไป ซึ่ง Test Double มีหลายตัว คือ

Dummy <-- and="" fake="" mock="" p="" spy="" stub="">
ที่เขียนแบบนี้เพราะมีบทความจาก Robert C. Martin ที่บอกว่า Mock เป็นประเภทหนึ่งของ Spy และ Spy เป็นประเภทหนึ่งของ Stub และ Stub เป็นประเภทหนึ่งของ Dummy แต่ว่า Fake เป็นประเภทที่แตกต่างออกไป (ทั้งนี้ควรจะอ่านบทความควบคู่ไปด้วย เพื่อความเข้าใจมากขึั้น มิฉะนั้น อาจจะเข้าใจผิดได้ เช่น ถึงแม้ Stub จะเป็นประเภทหนึ่งของ Dummy แต่ว่าการใช้ในการทดสอบก็ต่างกัน เพราะว่า Dummy มักใช้เป็น parameter ในการส่งเข้า method แต่ว่า Stub เราใช้แทน class เพื่อให้ทำงานบางวัตถุประสงค์)

ทั้งนี้จากบทความเอง ก็ช่วยให้เรารู้ว่าโดยปกติการเขียน unit test เค้ามักจะใช้ Stub กับ Spy ส่วน Dummy ใช้น้อยมาก และจะใช้ Mock น้อยมากๆ เนื่องจาก syntax ในการเขียนที่ดูยุ่งๆ ของ Mocking Tools (ตามบทความนะจ๊ะ แต่เราก็รู้สึกแบบนั้น)

ก็ถือเป็นการเปิดหูเปิดตาในการทำ Unit Test อย่างมาก

Reference:
The Little Mocker

.Net Unit Test Framework

พอดีเพิ่งได้มีโอกาสมาลองศึกษา .Net และต้องศึกษาเฉพาะส่วน unit test โดยเฉพาะ และได้ลอง search ดู ซึ่งในเวป Microsoft ทำไว้ค่อยข้างดีทำตามได้เลย แต่ก็ขอสรุปสั้นๆ ให้เข้าใจดังนี้

1. การจะสร้าง Unit Test ใน .Net จะเป็นลักษณะสร้างเป็นโปรเจ็คต่างหากใน solution เดียวกัน โดยเลือก template เป็น Unit Test Project ซึ่งตัวอย่างของ Microsoft ก็จะสร้างเป็น C# แล้วเลือกไปเมนูที่ Test ตอนสร้างโปรเจ็ค (ซึ่งเข้าใจว่าไม่จำเป็นที่จะต้องแยกเป็นคนละโปรเจ็ค เพียงแต่จะต้องใส่ using Microsoft.VisualStudio.TestTools.UnitTesting; เพื่ออ้างอิงถึง library ที่ต้องใช้ในการทดสอบ แต่ที่แยกเป็นคนละโปรเจ็ค เพื่อแยกส่วนที่จะเป็นตัวโปรแกรมจริงๆ ออกจากส่วนทดสอบ)

2. แล้วเลือก Add Reference... เป็นโปรเจ็คที่ต้องการจะทดสอบ

3. สร้าง class ใหม่ สำหรับเป็น unit test ซึ่งจะต้องใส่ attribute [TestClass] และ [TestMethod] ไว้ที่ class และ method ที่ต้องการให้ run เพื่อทดสอบ

4. ส่วนการ run test ให้ใช้ Test Explorer ในการ run จากเมนู TEST > Windows > Test Explorer

ตัวอย่างของ class ที่ใช้ทดสอบ

// unit test code
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace BankTests
{
    [TestClass]
    public class BankAccountTests
    {
        [TestMethod]
        public void TestMethod1()
        {
        }
    }
}

นอกจากนั้นยังสามารถใส่ attribute อื่นๆ ได้อีก เช่น [ExpectedException(typeof(ArgumentOutOfRangeException))] ดังนี้ 

//unit test method
[TestMethod]
[ExpectedException(typeof(ArgumentOutOfRangeException))]
public void Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange()
{
    // arrange
    double beginningBalance = 11.99;
    double debitAmount = -100.00;
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);

    // act
    account.Debit(debitAmount);

    // assert is handled by ExpectedException
}

Reference:
Walkthrough: Creating and Running Unit Tests for Managed Code Using Microsoft.VisualStudio.TestTools.UnitTesting Members in Unit Tests
Using the Assert Classes
Anatomy of a Unit Test