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.

Related Posts:

  • [心得文] 自動測試與TDD實務開發 Day2 Day2 的教學順序是先教我們怎麼使用Selenium做Web-Testing;中間則是介紹了FluentAutomation以及Page Objects;最後則是帶到了Refactoring。 而我的觀戰重點則是在於Refactoring。還記得以前我的Refactoring都是耗時費力,由上往下的設計模式。Refactor完也不敢保證有沒有side effect。Day2則是學到了如何有效攻克Refactoring。確實相當實用阿~ … Read More
  • [心得文] 自動測試與TDD實務開發 Day1 [前情提要] [反省] 學習是要正面主動積極的 其實半年前我就想報名這堂課,不過可惜最後因為幾個負面思考而打消了念頭,當時在心中埋下了一顆悔恨的種子,告訴自己說,下次再有這個機會請不要錯過。 終於,今年盼到了第三梯的課程,雖然價格提高了4成 =.= ,不過還是自己能夠負擔的範圍啦,當然就報囉。 剛好今年也給了自己一些明確的目標: 1.     2015Q4 要在公司教授Unit Testing的… Read More
  • [CI] [Jenkins] Jenkins的Nunit Plugin 無法讀取 Nunit3 的 formatNunit 在2015/12/1時 release 了 Nunit 3.0.1 於是我就採用了最新版的Nunit來寫Unit Test 但是發現Jenkins的 Nunit Plugin仍未跟著升級到3.0.1的format 參考了Jenkins的Issue https://issues.jenkins-ci.org/browse/JENKINS-27906 採用一個workaround 先將format 改成 nunit2吧 --… Read More
  • 2015 Trend University開課記錄_Unit Testing [Week1] Trend University 開課囉~後面還有7堂.......很高興今天順利地把第一堂課帶完花了一點時間讓大家都寫出第一支Unit Test希望學員們有把東西帶走ps. 昨天簡報課學到的大字流 講到哪秀到哪 今天馬上現學現賣!! [Week2] 實戰先從手工刻開始把不可測的External Dependency 變成可測試的重點在 偷天換日不過學員們花了一些時間習慣替換的方法 [Week3] week2的… Read More
  • [講師] 教導公司暑期實習生 Unit-Testing & TDD Introduction (1) 很榮幸在7月底幫公司的暑期實習生上了一堂課 Unit testing & TDD Introduction 由於Target Audience都是學生 姑且猜測他們寫code經驗比較不足 所以這次就安排了Unit-Testing的基礎課程以及讓他們實作練習的Coding Dojo 今天安排了整整4小時的課程 所以我把課程切分成三部分 :  1. 聽課 2. 實作 3. 小組報告 課程一開始 我先… Read More

0 意見: