熱鍵
- 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本身只有在模擬相依的物件而已。
比較物件屬性的方式
比較兩邊的物件包含子物件完全相同
1 |
expected.ToExpectedObject().ShouldEqual(actual); |
比較以expected為主的屬性去比較相對應的actual是否相同
1 |
expected.ToExpectedObject().ShouldMatch(actual); |
測試範例如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
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<Customer> { 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做比較
1 2 3 4 5 6 7 8 9 10 11 12 |
[Test] public void Divide_Zero() { var calculator = new Calculator(); var actual = calculator.Divide(5, 0); Action action = () => { calculator.Divide(5, 0); }; action.Should().Throw<YouShallNotPassException>(); //never use try/catch in unit test } |
寫測試一定要重構,不然在測試需求異動時和寫測試時會太花時間
因此不應該要有太多不會用到的資訊
讓測試的目標的意圖可以很明顯
要如何加快單元測試撰寫的速度很重要,這樣才有可能可以實踐單元測試
沒有時間是個問題,但是我們要去面對如何解決這個問題
要知道怎麼用工具怎麼寫比較快