2014-11-27

[讀書筆記] The pillars of good tests

[讀書筆記] The pillars of good tests

1. Writing trustworthy tests

2. Writing maintainable tests

[Maintainability]
Nonmaintainable tests are nightmares because they can ruin project schedules, or you risk losing the tests when the project is put on a more aggressive schedule.

test project 也會越來越多 如果難以維護的話
1. 會破壞Project Schedules
2. 不想再測試

2.1 Testing private or protected methods

Unit tests should be testing the public contract and public functionality of an object

應該要針對Public的來測

Solution:
(1) Making Methods Public
If a method is worth testing, it might be worth making it public, static, or at least internal, and defining a public contract against any user of it.
如果你的Method值得測試 那就將他變成Public的吧
      
(2) Extracting Methods to New Classes
如果Method包含了許多獨立的logic 就將他抽出吧

(3) Making Methods Static
如果Method沒有使用其他變數 可以考慮變成Static的

(4) Making Methods Internal
如果上述方法都失敗 有個最不推薦的方法
[InternalsVisibleTo("TestAssembly")]

Removing the method isn’t a good option because the production code uses the method too. Otherwise, there would be no reason to write the tests in the first place.

移掉Method其實不是一個好選項

2.2 Removing duplication

The “don’t repeat yourself” (DRY) principle
code有重複 就有壞味道

舉例來說:

上面看起來目前很合理
但如果寫了另一個Test

如果Production code 改變了 勢必要回來改這兩個TestMethod
導致更多的maintenance work
假設現在new完LogAnalyzer之後 要先呼叫Initialize()

那麼 我們必須在每個TestMethod裡都要加上呼叫
Initialize()的動作

Solution:
(1) Removing duplication using a helper method
透過GetNewAnalyzer()將 Initialize()封裝在這個Method
如此只要維護這裡即可

(2) Removing duplication using [SetUp]
另一種方法是寫在SetUp Method中
但是缺點就是 不是每個TestMethod都會用到這段邏輯
所以比較不推薦這種作法

2.3 Using setup methods in a maintainable manner

SetUp Method很好用 但是要注意會有以下問題:
(1) Initialize objects that are used by only some of the tests
(2) Having SETUP code that’s lengthy and hard to understand
      Refactor it

(3) Setting up fakes in the SETUP method
      要考量Fake Objects 是否每個Test Method都會用到

2.4 Enforcing test isolation

原則:
A test should always run in its own little world

如果Test Isolation沒有做好 勢必會相互影響導致錯誤的結果

以下介紹4種沒有隔離的狀況
(1) Constrained test order
      測試一定要按照某種順序
(2) Hidden test call
      在測試中呼叫其他測試
(3) Shared-state corruption
      共享的資源沒有回復
(4) External shared-state corruption       
      外部共享的資源沒有回復
Constrained test order
i. Flow Testing
   通常面對Flow Testing 會產生這種順序問題 所以一個建議的方式不要在UT中測試流程 或這是是採用Integration testing framework

ii. Laziness in cleanup
    也有可能是因為懶得清理資源 才導致必須按照某種順序來執行

Hidden test call
i. Flow Testing    
    同上

ii. Trying to remove duplication
    我們可能會為了不想要寫重複的code而在TestMethod中呼叫一個已經寫好的TestMethod 但是千萬不要這麼做

iii. Laziness in separating the tests
     別懶得抽出

Shared-state corruption


2.5 Avoiding multiple asserts

Create a separate test for each assert
Use parameterized tests
Wrap the assert call with try-catch


2.6 Avoiding testing multiple aspects of the same object

Create a full object to compare all the properties in one assertOverriding ToString(), let the test output much clearer

2.7 Avoiding overspecification in tests

OVERSPECIFY TESTS that Developers make:
Specifying purely internal behavior
Using STUBS also as MOCKS
Assuming an order or exact match when it’s not needed
xxx

3. Writing readable tests

xxx

2014-11-06

[讀書筆記] Interaction testing using mock objects

[讀書筆記] Interaction testing using mock objects

[前言]

在前一章Stubs 我們使用了Stub 來打破了Dependency
但是現實上 卻有很多的function是

沒有回傳值
沒有存狀態

針對這些Function該如何測試呢?

答案是 Mock Objects


1.1 Value-based vs. state-based vs. interaction testing



Value-based testing 
    Checks the value returned from a function.

State-based testing 
    Checks the noticeable behavior changes in the system under test, after changing its state.

Interaction testing
    Tests how an object sends input to or receives input from other objects—how that object interacts with other objects.

舉個例子:
假設有一個灌溉系統

Value-based testing 
    Check 水龍頭是否可以打開

State-based testing 
    Check 土壤濕度

Interaction testing
    在水龍頭端裝置一台監控設備 紀錄灌溉的起始結束時間以及水量 只需檢查監控設備的次數及水量是否正確

Sometimes state-based testing is the best way to go because interaction testing is too difficult to pull off.

State-based testing 有時是最好的測試方法 因為Interaction testing實在太難達到了

[Definition] 
Mock object
A mock object is a fake object in the system that decides whether the unit test has passed or failed. It does so by verifying whether the object under test interacted as expected with the fake object. There’s usually no more than one mock per test.


1.2 The difference between mocks and stubs


[Definition] 
Fake
A fake is a generic term that can be used to describe either a stub or a mock object, because they both look like the real object. Whether a fake is a stub or a mock depends on how it’s used in the current test. If it’s used to check an interaction (asserted against), it’s a mock object. Otherwise, it’s a stub.

Mocks 跟 Stubs最主要的區別如下圖:

Stub:
呼叫Assert的是 TestClass
code的例子:


Mock
用Mock Object來確認Test Pass or not


code的例子:


1.3: A simple handwritten mock example



假設新增一個需求:
當LogAnalyzer收到一個長度短於8的filename就呼叫外部WebService去記錄LogError

測試上 我們用MockWebService來替換掉外部WebService
此時我們要測的是 WebService是否確實有記錄到LogError


Why don't we write the tests directly inside the mock object code?
Reason:
1. We’d like to be able to reuse the mock object in other test cases, with other asserts on the message.
    要Reuse Mock Object

2. If the assert were put inside the mock object, whoever reads the test would have no idea what we’re asserting.
    寫在Mock裡 其他人會不知道在assert什麼


1.4 Using a mock and a stub together


假設再次新增一個需求:
如果WebService發生了Exception 系統要寄email給IT管理員

此時LogAnalyzer有兩個外部Dependence

如何測試當Exception發生時 有確實發送了Email?



Questions:

  • Why are we doing several asserts in a single test? How easy would it be to separate this test into three different tests with one assert each?Could the three asserts be combined into a single logical test?
  • It can be quite tedious to create manual mocks and stubs for each test or test class. How can we overcome that?
  • Couldn’t we have used the MockService from listing 4.1 as a stub?



1.5 One mock per test


Principle:

  • In a test where you test only one thing
  • Only one mock object in a test
  • Other fake objects are all stubs



1.6 Stub chains: stubs that produce mocks or other stubs


當一層接一層時 怎麼測試?
ex. 

你可能要寫 factory 跟 service兩個stubs
或者 Confuguration 跟 DBConfiguration兩個stubs

假如你想要替換掉 connstring
Solution:
1. 用Extract and Override    


2. 用Adapt Parameter Pattern


1.7 The problems with handwritten mocks and stubs


1. It takes time to write the mocks and stubs.

2. It’s difficult to write stubs and mocks for classes and interfaces that have many methods, properties, and events.

3. To save state for multiple calls of a mock method, you need to write a lot of boilerplate code to save the data.
<boilerplate : 照本宣科的規範;(新聞業)一成不變的陳腐文字>
為了在多次呼叫Mock Methods之後儲存狀態 需要寫很多code

4. If you want to verify all parameters on a method call, you need to write multiple asserts. If the first assert fails, the others will never run, because a failed assert throws an exception.
如果需要check 一個method的所有參數 需要多個 assert
但是只要一個assert Fail 就會中斷這次測試


5. It’s hard to reuse mock and stub code for other tests.


2014-11-03

[上課筆記] Think on your feet

Think on your feet

1. What

Think on your feet 著重的焦點是思考
能讓你迅速地理性思考 關鍵在於 "結構"

先打樁 列出要說明的Main Idea

再填入內容


2. Why

2.1 Think on your feet的好處?

幫助你思考清楚

表達想法的三個重點:

Clarity 清晰
    清楚地說明 讓人理解
Brevity 簡潔
    精準表達 
Impact 有力
    留下深刻印象

2.2 為什麼要運用計畫?

結構能讓你將一堆資訊變得井然有序
1. 集中焦點
2. 協助清晰

2.3 為什麼分成三部分?

1.說服力強
2.節奏流暢
3.印象深刻


3. How

3.1 結構格式:

    前言        
        陳述主題 宣告三個重點
        <第一印象要讓聽者牢牢記住>
        <要簡短有力>
    內文
       第一部分(結構) - 內容
       第二部分(結構) - 內容
       第三部分(結構) - 內容
    結論
       再次強調重述主題
        <最後印象要讓聽者牢牢記住>
        <要有型>
        <選出最棒的照片來定格>
        <結語要把核心主題再唸一次(但別解釋)>
        <最後讓聽者開心的笑>

3.2 6種包裝說服力的計畫

3.2.1 時鐘計畫
    用時間來安排主題
    例子: 
    早上,下午,晚上
    過去,現在,未來
    <時間的演進>
    2000年...., 2008年...., 2014年....
            
3.2.2 環球計畫
    用地理位置或是視覺位置來安排
    例子:
    台北, 台中, 台南
    住家, 公司, 公共場所
    頭, 手, 腳
    
3.2.3 三角計畫
    用不同的角度,面向或觀點來安排
    好處:
    1. 展現客觀論點
        例子:
         新產品是否成功的評估:
         技術, 行銷, 市場
    2. 顯示深思熟慮
        例子:
         創業要考慮的三個面向:
         想法, 團隊, 資金
    3. 表達各種觀點
        例子:
         教育的三種腳色:
         家長, 老師, 兒童    

3.2.4 變焦計畫
    改變觀點 用越來越廣或越來越窄的角度來安排
    越來越廣 擴大視野
    先看特定事件, 以更廣的角度來說..., 整體而言....
    越來越窄 聚焦細節
    整體而言...., 然而.... (稍微縮小範圍) , 具體而言....

    當觀點相同 採取的策略是直接認同
    當觀點不同 採取的策略是間接認同

    <或許有些人想法跟你一樣>
    <我過去的想法也跟你一樣>

    少用 <但是/可是> 帶有負面情緒
    多用 <然而/如果/同時>

3.2.5 鐘擺計畫
    描述兩邊極端立場 再轉向中間立場
    先描述完全相反的選擇 
    讓聽者趨向合理的中庸之道
    再帶領聽者往中間趨近

    激進的鐘擺 - 捍衛現狀
        讓聽者覺得兩邊極端的作法都不好 只有中庸最好
        通常答案就是維持現況
     
    溫和的鐘擺 - 折衷
        不去攻擊極端 試著在兩極之間找到平衡

3.2.6 收益計畫
    強調對聽者有益的好處
    用來宣傳, 推銷, 說服

    例子:
    推銷新東西, 你一定要告訴聽者這東西有什麼好處, 而不是提這東西有什麼特點
    <把重點放在益處>

    創造說話的動力 可以這樣安排:
    先提排名第二的功能
    再提最弱的功能
    最強的功能放在最後 塑造高潮

    反之 反收益計畫
    如果你不這樣 就會有以下缺點
    強調聽者如果不做的壞處   

3.3 讓想法更生動的作法

    圖景計畫             

             利用比喻及舉例協助聽者理解 進而記住    

    對比計畫

             利用兩種完全相反的極端來說明比較
             <後面推翻前面>
             <結局出乎意料>

   骨牌計畫

             描述因果關係:
             三因一果, 連鎖反應, 一因三果

    W5

             Who, What, Where, When, Why and How


3.4 整合

    3.4.1 銜接技巧
        肯定
             肯定對方,事實 認同對方感受
              <每個人行為的背後一定有某個"正面"的意圖>
             例子:
             我可以理解你為什麼擔心
             你提出XXX 是個很好的觀點           
        詢問
             幫助聽者組織問題
             請對方舉例
             用封閉式的問題取得資訊
        調整
             用關鍵字
             挑整層次(變廣 變窄 側面切入)
             拉回主題

    3.4.2 找出核心主題
        以聽者視角去思考主題
        1. 想想聽者的背景知識
        2. 猜測聽者的希望期待
        3. 列出聽者的擔心害怕

    3.4.3 標題
       簡短有力的標題
       用主動語氣

2014-10-23

[讀書筆記] The art of Unit Testing - ch2 - A first unit test

[讀書筆記] 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 能夠一目瞭然問題出在哪裡?

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.org


2.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比對

Writing UT Process




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
此時就能用[ExpectedException]來測試是否有丟出相關Exception

預期要測Exception 就不用Assert (其實已經含在[ExpectedException]中)

For example:

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"

2.5.4 Setting test categories

我們也能夠透過[Category("A")]將Test分組
如此可透過NUnit測試特定Category

For example:

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用到的資源

2014-10-22

[讀書筆記] The art of Unit Testing - ch1 - The basics of unit testing

[讀書筆記] The basics of unit testing

1.1 Unit Testing - the classic definition

What is the classic definition?
A unit test is a piece of a code (usually a method) that invokes another piece of code and checks the correctness of some assumptions afterward.
If the assumptions turn out to be wrong, the unit test has failed. 
A "unit" is a method or function.

傳統的Unit Test就是寫另外的code去check你的production code是否正確
一個Unit就是以一個method或function為單位

傳統上大部份公司的現況:
1. Rely on System and Integration Test
    倚靠Integration Test來測
2. Manually testing
    手測
3. Test by using the end product
    利用UI來測

其實我們或多或少都一定寫過測試
如下圖:

我們可能會寫個WinForm或是WebForm透過UI呼叫我們寫的code來驗證正確性

實際上這樣的測試離Good Unit Test 還有一大段距離


1.2 Properties of a good unit test

所以到底Good Unit Test有什麼樣的特性呢?

  • It should be automated and repeatable.
  • It should be easy to implement.
  • Once it’s written, it should remain for future use.
  • Anyone should be able to run it.
  • It should run at the push of a button.
  • It should run quickly.
  • 要能夠自動化
  • 要容易實作
  • 一旦寫好未來都能使用
  • 每個人都能執行它
  • 按個button就能執行
  • 要能夠快速地執行


各位可以問問自己以下的問題:

  • Can I run and get results from a unit test I wrote two weeks or months or years ago?
  • Can any member of my team run and get the results from unit tests I wrote two months ago?
  • Can I run all the unit tests I’ve written in no more than a few minutes?
  • Can I run all the unit tests I’ve written at the push of a button?
  • Can I write a basic unit test in no more than a few minutes?


問問自己 如果有任何一題的答案是no
那麼你寫的test 可能就不屬於Unit Test


1.3 Integration tests

What is the Integration Test?

Integration testing means testing two or more dependent software modules as a group.

Integration test 就是把兩個以上的modules組合起來一起測試

If the test fails, all the parts fail together; if it succeeds, the parts all succeed.

所以Integration Test 面臨的問題是
If the test fails, all of these software components fail as a team, and it can be difficult to figure out what caused the failure of the overall operation.

因為要死就一起死 很難抓出root cause
如下圖:



Integration Test的問題就在於有很多的Failure points你必須一一排除

1.3.1 Drawbacks of integration tests compared to automated unit tests

讓我們回想剛剛自問的問題:
Can I run and get results from a unit test I wrote two weeks or months or years ago?
A: code change是相當常見的 在改完code之後 是否知道有side effect? 所以需要Unit Testing !!!

作者將此稱為 "accidental bugging"

Regression
A regression is a feature that used to work and now doesn’t.
過去可以work 現在不行

Good tests should be easily executed in their original form, not manually.

Can any member of my team run and get the results from unit tests I wrote two months ago?
A:如同第一題 只是這是改別人的code
    大部分人都會擔心Legacy code
    因為會怕改Legacy code又造成side effect

Legacy code
Legacy code is defined by Wikipedia as “source code that relates to a no-longer supported or manufactured operating system or other computer technology,” but many shops refer to any older version of the application currently under maintenance as legacy code. It often refers to code that’s hard to work with, hard to test, and usually even hard to read.

Good tests can be accessed and run by anyone.

Can I run all the unit tests I’ve written in no more than a few minutes?
A:如果test需要很久 那麼你也就不會很常去測試了
    這邊講的是 便利性

Good tests should run quickly.

Can I run all the unit tests I’ve written at the push of a button?
A:如果不行 那代表你必須經過重重難關才能測試(ex.設定 or 雜事) 如果不方便 那麼你也不想去測試了
    這邊講的是 便利性

Good tests should be easily executed in their original form, not manually.


Can I write a basic unit test in no more than a few minutes?
A:測試的scope越大 牽扯的module越多 測試就越難寫
    如果測試越難寫 那麼你也不想去測試了
    這邊講的是 便利性

其實這段也偷偷暗示我們應該要使用Unit-Testing Framework來寫測試才會方便

Good tests against the system should be easy and quick to write.


1.4 Good Unit Test

引言至此 作者終於要帶出他心目中 Good Unit Test的定義了

  • A unit test is an automated piece of code that invokes the method or class being tested and then checks some assumptions about the logical behavior of that method or class.
  • A unit test is almost always written using a unit-testing framework.
  • It can be written easily and runs quickly.
  • It’s fully automated, trustworthy, readable, and maintainable.
好的Unit Testing就是 使用unit-testing framework 自動化地去測logical behavior
必須很方便的實作測試 執行測試也必須很快看到結果

Logical code
Logical code is any piece of code that has some sort of logic in it, small as it may be.

It’s logical code if it has one or more of the following: an IF statement, a loopswitch or case statements, calculations, or any other type of decision-making code.

只有logical code需要測試

反例:
像Java的 get/set 如果沒有內含邏輯的話 其實不用測它


1.5 A simple unit test example

這個章節 作者寫了一個測試範例 但他並沒有使用Unit-testing framework
我們可以看看就算沒有Unit-testing framework 測試的邏輯還是一樣 但是就是麻煩了些 所以有framework的協助 會讓各位更方便地寫Unit Test 才會讓大家有動力去寫


1.6 Test-driven development

大部分的人是在實作完production code之後才開始寫測試
但作者相當推薦先寫測試再寫code
這種方式就稱之為TDD 

傳統的coding process如下圖:
TDD的coding process如下圖:
TDD的流程如下:

1 Write a failing test to prove code or functionality is missing from the end product.
    先寫測試 所以沒有production code的結果就是FAIL

2 Make the test pass by writing production code that meets the expectations of your test.
    接下來我們應該要想辦法讓Test PASS

3 Refactor your code.
    經過幾個Test Pass之後 或許開始發現可以refactor一些code
    此時就能放心地refactoring

Refactoring
Refactoring means changing a piece of code without changing its functionality.
If you’ve ever renamed a method, you’ve done refactoring.
If you’ve ever split a large method into multiple smaller method calls, you’ve refactored your code.
The code still does the same thing, but it becomes easier to maintain, read, debug, and change.

這邊其實帶出一個Unit-testing的優勢就在於我們能夠放心地refactoring 因為改壞馬上就被Unit Test抓出來


1.7 Summary

作者不斷的想強調 什麼是Good Unit Test
因為很重要 所以要一直重複提
What is a good unit testing?
  • It’s an automated piece of code that invokes a different method and then checks some assumptions on the logical behavior of that method or class.
  • It’s written using a unit-testing framework.
  • It can be written easily.
  • It runs quickly.
  • It can be executed repeatedly by anyone on the development team.

2014-05-13

[徵合購] Mountain Buggy Nano in maxis-babywelt

大家好 我又來徵合購啦
上次的網站請大家把他忘記 我換另一家購物網站了
maxis-babywelt
http://www.maxis-babywelt.de/index.php?language=gb

為什麼呢? 因為我要的推車這邊還有貨
以下是我要的推車
Mountain Buggy Nano
http://mountainbuggy.com/us/Products/buggies/nano#.U3Hi1PmSySo

你可以把他想成最近很夯的Babyzen YoYo 稍微放大版
但是價格便宜很多 我覺得他很有潛力變成下一個YoYo
目前台灣還沒有人代理 美國也呈現缺貨的狀態

目前我跟這個網站的客服談來談去 終於確定了規格
2個座椅+1台推車 或是 1個座椅+2台推車 再加其他小東西
只要在30KG內 運費都是79.99歐元

我自己會買1個汽座+1台推車
所以有興趣的人合購這台車或是汽座 或是這網站上的其他東西
請聯絡我一下 我們可以再談怎麼share運費
謝謝各位囉

別人的推薦
http://ayz75.pixnet.net/blog/post/40556437-%E7%91%AA%E8%B1%86%E7%9A%84%E6%96%B0%E6%8E%A8%E8%BB%8A---mountain-buggy-nano

Mountain Buggy Nano vs Babyzen YoYo
http://www.bestbuggy.co.uk/2014/03/mountain-buggy-nano-vs-babyzen-yoyo/

Youtube 上的介紹影片
https://www.youtube.com/watch?v=mbvxHoyj13Q

2014-05-08

[讀書筆記] The Practice of Programming - Notation

Notation
SlideShare上的投影片分享



其實這個章節我只有抓到幾個重點

1. 如果你寫很多code去執行一個平庸的工作或是在處理流程上遇到麻煩
    或許你是用錯語言

2. 如果一個適合的語言尚未存在 這就是個機會寫出一個適合的語言

3. Sample : Transit different format data

    假設有兩種不同格式的data
    (1)
 
    (2)

    如果你是針對這兩種格式做pack 與 unpack的處理
    function 大概會長下面這樣
   

    有沒有發現每個type 必須handle parse的邏輯
    所以作者想了一個方法 自訂一種格式format string
    
    c : char
    s : short
    l : long

    如此就能將重複的邏輯抽出 並利用此格式來處理不同type的資料

    
    
    外層是呼叫pack 並給入相對應的format
    外層靠著 "cscl" 告知pack 這次傳入的格式

4. 對於Micros
    作者雖然不推薦使用 但他仍認為Micro有適合的地方 : 
    (1) Micro 適合用在定義文字
    (2) Be practical and be easy to produce.
    (3) Portable

5. 很多問題或許換個方式描述 就能輕易地解決 這就是Notation的魔力

2014-05-07

2014-04-25

2014-04-24

[讀書筆記] The Practice of Programming - Portability

Portability 
SlideShare上的投影片分享



Why do we worry about portability? 
1. Less maintenance and more utility

2. Environments change
    環境會變 OS會升級

3. A portable program is a better designed program
    同意 一個可移植性的程式 本身抽象化的程度也比較高 設計上會比較好

程式語言
1. 照著標準走 

2. 照著主流走

3. 注意各data type的size 但彼此的 size關係不脫離下列
    sizeof (char) <= sizeof (short) <= sizeof (int) <= sizeof (long)
    sizeof (float) <= sizeof (double)

4. 賦值的順序不一定一樣 n = (getchar() <<8) | getchar()
    左邊的getchar()不一定先叫用

5. 注意char的 sign or unsign

6. 注意Struct的size, 計算大小請直接用Struct來計算, 不要用變數相加的方式
    Yes => sizeof (struct X)
    No  => sizeof (char) + sizeof(int)

7. Try several compilers
    既然考慮移植性 就在不同的compiler間 compile看看吧

Headers and Libraries
1. 使用標準lib

2. Header若太肥太亂 請把共同的程式碼抽出來 針對不同環境 把不同的Header集中
   換句話說 共同的程式碼應該在不同環境下都能使用 但是針對不同環境的Header Files 請將它們抽出放到各自的環境上 

3. 如果你取的變數名稱跟標準lib Header定義的一樣 你的名稱會被header汙 染 但是不要跟標準抗爭 請使用別的名字繞過去 

Program Organization
有兩種方法能達到移植性
1. Union
    利用條件式編譯 把所有環境的可能性放在一起
2. Intersection
    抽出共同的部分 根據不同環境塞不同header 作者相當討厭條件式編譯 認為這造成maintain上的困難 

如何避免條件式編譯 看看是否真的有其必要 

Isolation
1. 老話重彈 針對不同環境客製化不同的files
2. Hide system dependencies behind interfaces 盡量抽象化 例如 The I/O Libraries : 我們只會知道Read Write等 最底層最依賴OS的實作放在各語言中
3. 盡量使用Standard Language Library 而不是WINAPI

Data Exchange
作者贊成直接用String做資料交換

Byte Order
有時無可避免使用Binary Data
事實上Binary Data 也比較快比較小 但要注意 little-endian 跟 big-endian的問題
重點是 Sender跟Receiver要講好格式

Portability and Upgrade
1. Change the name if you change the specification 
   若改規格就改名字吧 Name要名副其實
2. Maintain compatibility with existing programs and data 
   要跟舊版保有相容性 就像Java每一版都還會留著舊版API 但在JDK中會註明不建議使用

Internationalization
1. 不要假設ASCII
    用Unicode吧 再用UTF-8轉 c/c++ 就用Wide characters吧
2. 不要假設English
    可以像趨勢的作法 將wording跟UI都抽出 到時方便替換