2016 PHPConf Day 2:The Testing Un-Training (Workshop) - Sebastian Bergmann

Start from very beginning

  • 要取有意義的名字,可直接用中文
  • test 作為 method name 的 prefix 或是使用 @test
  • method 內呼叫真的要做的邏輯,實際去呼叫該被 new 的 class 和 method 並對結果做 assertion
  • Tell PHP to find PHPUnit source code by bootstrap,不一定只能從 composer 安裝
  • Use phpab to generate autoloader, because the composer autoload contains too much logic.
phpab -o src/autoload.php src
./build/tools/phpunit.phar --bootstrap src/autoload.php tests
./build/tools/phpunit.phar --generate-configuration
  • 沒有任何 assert 對測試而言是正確的還是錯誤的?根據 phpunit.xml 可以設定 strict 模式,如果沒有 assert 會得到 risky
  • code coverage 會紀錄測試程式有走過的每一行
  • 用測試程式產生文件可用來針對每個 class method 進行溝通
phpunit -c build
Don’t test private method and private attribute, because private is for public to use, so you just need to test the public method.
Static method is death for testability, but use dependency injection can mock the input.


使用替身來做測試:以拍電影為例,印第安那瓊斯的 Harrison Ford 在地球上只有這一位,如果要他去做危險的特技動作但是機關設計都還沒做過測試,那我們可能就會損失這位演員。所以會有特效替身的工作出現。

Types of test doubles

Everything is Mock, 都使用 createMock() getMock() 但根據行為的區別實際意義可區分:

  • stub:can be configured as needed for exercising the SUT
  • spy:stub that records SUT(被測系統)<=> DOC(依賴元件)communication
  • mock:The stub verify SUT <=> DOC communication with expectations

  • no test double required - 直接 new target class and use the method
  • createMock create a object just like your class

期望 真正的物件應該要和 mock 的物件有一樣的行為和結果

Don't make attributes public, because it could change outside directly without through the class method.

除了 PHPUnit 內建的以外,也可以選用其他 mock framework 混用:

  • prophecy
  • phake
  • mockery

SPY set expected in the end, Mock do it before

not public, static method can't to be mock

What should mock, what shouldn't : testing all your production code, and mock all the dependency, but you don't need to mock value object.

Don’t try to mock PHP native functions, just mock the whole object

如何測試 closure 程式?講者說不能測也不用測,因為那是外部的行為。jaceju 作法是:


DBUnit is used to compare real db tables and dbunit’s dataset.

Implements createDefaultDBConnection() for what you want REAL database to test.

Implements getDataSet() for your expected dataset, it can be such as php array, csv files, or xml.

DBUnit 已經很久沒有維護了。

TDD helps focus the problem and think, avoid write code unused. Make it clear on what you need to do. Use TDD force the team members communicate. Team members only care about your test code, not care you write test first or production code first.

A good test, 要取有意義的名字,並且一個測試只測一個邏輯。

  • The test you get from the team member : CI/CD, run all the test for each push.
  • The test you get from the composer : look at them to know how to use 不要直接使用你找到的第一個 看是不是還有人在維護更新 看這位作者是不是可靠 用有人在用的、有回報 BUG 的,也可參考覆蓋率

測試是開發的一環,如果有東西要找外包做應該在合約中註明 source code 要包含測試。

Test all the public methods. 非常簡單的邏輯要寫的測試一定也非常簡單,那久不要省,因為簡單的邏輯不一定永遠都會簡單。

How to start with legacy code without any test?照感覺。去測覺得最重要的 / 容易出錯的程式。越不敢改動的程式就越有測試的價值。常常改動的部份也應該測試。用靜態分析的工具找出程式的關聯性,找出哪個程式是很常被使用的。跟錢有關的通常是重要的應該要被測試,或是參考團隊的 issue tracker。

Legacy code 因為有用、賺錢、重要所以才需要重構、才需要被測試保護。

Legacy code is the code that works.
Legacy is valuable code that we feel afraid to change.

Characterization Tests

Characterization tests area an attempt to lock existing behavior into ana untested or undocumented system.

Decouple test code from test data. Extract data to a data provider.

Dimension Zero - Why test ?

  • Don't put the bug in the software, then you don't need to debug.
  • Technical Debt

Types of software testing

  • Dynamic vs Static (真正去執行或是靜態分析)
  • Functional vs Non-Functional
  • Black-box vs White-box (How much knowledge should we use? )
  • Development vs Production (A/B testing only run on Production)
  • Manual vs Automated

The Three Dimensions of Testing

  • Role - what do we want achieve with the test
  • Scope - what is the environment in which we perform the test ?
  • implementation -

Role:Acceptance Test

Does our software do the right thing

helps developers and domain experts to understand and agree on what is built

Scope:end 2 end test

Does the system as a whole work

Exercises a web application by sending it a real HTTP request and inspecting a real HTTP response returned by it.

Scope: Edge 2 edge test

Role: integration test

  • is our software correctly integrated?
  • do the the units of our software interoperate correctly
  • do our abstractions over third-party code work
  • does our communicateion with other code work

Role: Unit test

  • is our software well crafted ?
  • do the units of our software work correctly in isolation from each other
  • arethe unit of our software convenient tot work with and easy to test

Keep the code clean, then the test will not be painful.

phpunit --testdox



只用 assertTrue 缺乏可讀性 盡量選用準確的 assert method

test 都應該要有 assertion

The secret in testing is in writing testable code.
Keep it simple, stupid.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.