[讀書筆記] A first unit test
2.1 Frameworks for unit testing
Doing things completely manually would be error-prone and time-consuming, and people would defer doing that as much as possible.
手動出錯的機會很大 又浪費時間
所以請讓Unit-testing framework來協助你寫測試吧
2.1.1 What unit-testing frameworks offer
所以unit-testing framework到底你提供你什麼服務呢?
先想想目前手寫的測試(沒用framework)有怎樣的缺點
- They were not structured. (
每次測試你可能都是用不同介面來測試 ex. Webform, Winform or WinConsole)
- They were not repeatable. (無法執行過去的測試)
- They were not on all your code. (沒有測到所有的code 如果寫UT是很方便的 RD才會盡可能地多寫UT 增加Coverage)
Unit-testing Framework能幫助你解決上述問題
Framework的介入是獨立的 你能在你的TestProject寫完Test Case 再透過統一的介面去執行測試
以下列出了Framework導入後對RD的協助:
1. Write tests easily and in a structured manner.
Framework都已經定義好結構跟使用方法
所以寫UT時 只要繼承或是follow API 就能寫出UT
非常方便且結構化
2. Execute one or all of the unit tests.
透過GUI或是command 執行所有的tests
重點是能夠自動化
3. Review the results of the test runs.
跑完test之後的Report 能夠一目瞭然問題出在哪裡?
- They were not repeatable. (無法執行過去的測試)
- They were not on all your code. (沒有測到所有的code 如果寫UT是很方便的 RD才會盡可能地多寫UT 增加Coverage)
Unit-testing Framework能幫助你解決上述問題
2.1.2 The xUnit frameworks
C++ : CppUnit / (GoogleTest)JAVA : JUnit
.NET : NUnit
2.3 First steps with NUnit
2.3.1 Installing Nunit
先去Nunit官網下載最新的Nunit並安裝
http://www.nunit.org2.3.2 Loading up the solution
打開NUnit GUI 之後 選擇Open Project 就能將你寫的Test Project 載入注意!! 這裡載的是Test Project 不是ProductionCode Project
接下來就能開始執行NUnit了
2.3.3 Nunit attributes
寫UT之前 先來了解NUnit 有哪些attribute可以用Naming
在寫UT時 最好也follow建議的naming style (潛規則)
Project :
Create a test project named [ProjectUnderTest].Tests.
Class :
For each class, create at least one class with the name [ClassName]Tests.
Method :
For each method, create at least one test method with the following name:
[MethodName]_[StateUnderTest]_[ExpectedBehavior]
MethodName : The name of the method you’re testing
StateUnderTest : The conditions used to produce the expected behavior (這個method要執行的動作)
ExpectedBehavior : What you expect the tested method to do under the specified conditions (預期的測試Return Value)
For example:
有個Method叫做 IsValidLogFileName, 這個method的目的是要驗證filename是否合法, 接下來我們要寫一個UT去測這個method, 預期結果為True
所以UT的method name 應該為 :
IsValidFileName_validFile_ReturnsTrue
2.4 Writing our first test
1. Add Reference
要在Test Project 使用到NUnit必須先using NUnit.Framework
注意!! 不是加在Production Code
2. [TestFixture]
請在每個Test Class上方加上[TestFixture]
3. [Test]
請在每個Test Method上方加上[Test]
注意!! NUnit的test method都必須為 void 且不帶任何parameters
ex. public void IsValidFileName_validFile_ReturnsTrue(){...}
4. Arrange, Act, and Assert
每個Test Method內都需要包含這三個內容:
- Arrange objects, creating and setting them up as necessary.
- Act on an object.
- Assert that something is as expected.
For example:
Create出一些資源 設一些設定
呼叫Production code中待測的這支method
透過Assert 比對結果是否符合自己預期
Assert有很多條件跟API能呼叫
請到官網Document查詢
目前我採用的是NUnit 2.6.3版
http://www.nunit.org/index.php?p=assertions&r=2.6.3
以下就先列AreEqual跟AreSame的不同點
Assert.AreEqual
這個是值比對
Assert.AreSame
這個是Reference比對
2.5 More Nunit attributes
2.5.1 SetUp and TearDown
For unit tests, it’s important that any leftover data or instances from previous tests are destroyed and that the state for the new test is recreated as if no tests have been run before.
一個很重要的原則:
每個測試都像是新的一樣 不要殘留之前的data
所以我們需要SetUp跟TearDown的觀念
[SetUp]
This attribute can be put on a method, just like a [Test] attribute, and it causes NUnit to run that setup method each time it runs any of the tests in your class.
每次執行[Test]之前 就會執行[SetUp]
你可以把[SetUp]想成Constructors
[TearDown]
This attribute denotes a method to be executed once after each test in your class has executed.
每次執行[Test]完之後 就會執行[TearDown]
你可以把[SetUp]想成Destructors
[SetUp]跟[TearDown]是每次執行[Test]都會執行的
那有沒有類似的概念是 for Class [TestFixture]的?
[TestFixtureSetUp]
執行[TestFixtureSetUp] Before all [Test]
[TestFixtureTearDown]
執行[TestFixtureTearDown] After all [Test]
[TestFixtureSetUp]或[TestFixtureTearDown]的用途是當資源setting up 或 cleaning up花太久時 只想執行一次時使用
如下圖:
2.5.2 Checking for expected exceptions
- The expected exception message is provided as a parameter to the [ExpectedException] attribute.
- There’s no Assert call in the test itself. The [ExpectedException] attribute contains the assert within it.
- There’s no point getting the value of the Boolean result from the method because the method call is supposed to trigger an exception.
有時候我們會預期什麼情況下會丟出Exception
2.5.3 Ignore tests
Sometimes you’ll have tests that are broken and you still need to check in your code to the main source tree.
有時候你不想要Fail的Test中斷你的其他test 可以善用[Ignore]
設定[Ignore]之後 Test就能忽略掉這個TestMethod
在NUnit GUI 看到的顏色就會變成黃色
For example:
如果Ignore內寫了"內容"
[Ignore("XXX")]
就會在GUI中的Test Property中顯示Reason="XXX"
設定[Ignore]之後 Test就能忽略掉這個TestMethod
在NUnit GUI 看到的顏色就會變成黃色
For example:
如果Ignore內寫了"內容"
[Ignore("XXX")]
就會在GUI中的Test Property中顯示Reason="XXX"
2.5.4 Setting test categories
2.6 Indirect testing of state
State-based testing
State-based testing (also called state verification) determines whether the exercised method worked correctly by examining the state of the system under test and its collaborators (dependencies) after the method is exercised.
有時候狀態的測試不是直接的
如同下列情況
有個Class Calculator 他有
兩個Method :
public void Add(int number);
public int Sum();
一個Property:
private int sum=0;
每次呼叫Add 累加完之後的值會存在sum中
Add return void 這樣我們該如何驗證Add呢?
Solution:
要切兩個Test Case
1. Default Sum應該要為0
2. 呼叫Add之後 Sum應該要正確
注意!! Add_CalledOnce_SavesNumberForSum()
因為這個測試主要還是測試Add的邏輯
所以最好還是以Add來命名
如下圖:
2.7 Summary
作者希望大家記住下面四點:
- It’s common practice to have one test class per tested class, one test project per tested project, and at least one test method per tested method.
- Name your tests clearly using the following model: [MethodUnderTest]_[Scenario]_[ExpectedBehavior].
- Use the [SetUp] and [TearDown] attributes to reuse code in your tests, such as code for creating and initializing objects all your tests use.
- Don’t use [SetUp] and [TearDown] to initialize or destroy objects that aren’t shared throughout the test class in all the tests, because it makes the tests less understandable. Someone reading your code won’t know which tests use the logic inside the setup method and which don’t.
一個Project就對應一個TestProject
一個Class就對應一個TestClass
一個Method至少要對應一個TestMethod
Follow [MethodUnderTest]_[Scenario]_[ExpectedBehavior] 規則
善用[SetUp]及[TearDown]對資源操作
相反地也不要在這兩處放置非所有Test用到的資源
0 意見:
張貼留言