Posted on Leave a comment

單元測試 – 寫測試的基本原則

熱鍵

  • Alt+Enter: Quick+Action
  • Ctrl+R,M 抽方法出來
  • code snippets / live template
  • constructor: ctor
  • property:prop
  • console.writeLine)():cw
  • ctrl+R,F: Extract Field
  • Alt+Insert
  • 循環剪貼簿:ctrl+shift+V

測試替身有下面三種

  • stub:不做驗證,單純只做模擬相依物件的行為
  • mock:一開始就要把所有的都定義清楚,應該要呼叫那個方法,所有的值一定要一模一樣,否則就會報錯(嚴格,敏感,不穩定)
  • spy: 則是把所有的互動先做完,只驗要驗的,剩的沒有測就是都算過,差異是一個從嚴一個從寬。(寬鬆)

因此mock和spy本身含有驗證(Assertion),而stub本身只有在模擬相依的物件而已。

比較物件屬性的方式

比較兩邊的物件包含子物件完全相同

expected.ToExpectedObject().ShouldEqual(actual);

比較以expected為主的屬性去比較相對應的actual是否相同

expected.ToExpectedObject().ShouldMatch(actual);

測試範例如下
namespace AssertionSample
{
[TestFixture]
public class AssertionSample
{
private CustomerRepo customerRepo = new CustomerRepo();

//比較物件屬性的方式
[Test]
public void CompareCustomer()
{
var actual = customerRepo.Get();
var expected = new Customer
{
Id = 2,
Age = 18,
Birthday = new DateTime(1990, 1, 26)
};

//CollectionAssert也是在比較物件的位置,所以也會有相同的問題
expected.ToExpectedObject().ShouldEqual(actual);
}

//比較集合的方式
[Test]
public void CompareCustomerList()
{
var actual = customerRepo.GetAll();
var expected = new List
{
new Customer()
{
Id = 3,
Age = 20,
Birthday = new DateTime(1993,1,2)
},
new Customer()
{
Id = 4,
Age = 21,
Birthday = new DateTime(1993,1,3)
}
};

expected.ToExpectedObject().ShouldEqual(actual);
}

//組合式物件的比較
[Test]
public void CompareComposedCustomer()
{
var actual = customerRepo.GetComposedCustomer();

var expected = new Customer()
{
Age = 30,
Id = 11,
Birthday = new DateTime(1999, 9, 9),
Order = new Order {Id = 19, Price = 91},
};

expected.ToExpectedObject().ShouldEqual(actual);
}

//回傳的資料的PROPERITY很多,但是我們只想比其中幾項
[Test]
public void PartialCompare_Customer_Birthday_And_Order_Price()
{
var actual = customerRepo.GetComposedCustomer();

//有自定型別的一定要改成匿名型別
var expected = new
{
Birthday = new DateTime(1999, 9, 9),
Order = new {Price = 91},
};

//使用匿名型別 去比較以expected為主去比較相對應的actual是否相同
expected.ToExpectedObject().ShouldMatch(actual);
}
}

寫測試的規則


測試程式不含商業邏輯,所有的測試都應該是直述句
不應包含以下的元素:

  • prod business logic
  • 不含if, else, switch case等邏輯程式碼
  • 更不含try..catch
  • 不含for, while, foreach, do..while

善用assertion package

  • C#: expectedObjects,FluentAssertions
  • Java: Assert J

不要攤開properity做比較

[Test]
public void Divide_Zero()
{
var calculator = new Calculator();
var actual = calculator.Divide(5, 0);
Action action = () =>
{
calculator.Divide(5, 0);
};
action.Should().Throw();
//never use try/catch in unit test
}

寫測試一定要重構,不然在測試需求異動時和寫測試時會太花時間
因此不應該要有太多不會用到的資訊
讓測試的目標的意圖可以很明顯
要如何加快單元測試撰寫的速度很重要,這樣才有可能可以實踐單元測試
沒有時間是個問題,但是我們要去面對如何解決這個問題
要知道怎麼用工具怎麼寫比較快

Leave a Reply