[PHP]用PHPUnit进行行为驱动开发(Behaviour-Driven Development)
生活随笔
收集整理的這篇文章主要介紹了
[PHP]用PHPUnit进行行为驱动开发(Behaviour-Driven Development)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
PHPUnit的介紹可以翻翻前面幾篇文章。
本文參考文獻:
[Astels2006] A New Look at Test-Driven Development
*極限編程(Extreme Programming)最初的原則是測試所有可能發生錯誤的地方。
*現在極限編程的測試實踐已經進化到TDD(Test-Driven Development)
*但是工具依然強迫developer考慮測試用例和斷言,而不是考慮需求說明。
Dave Astels原文:
So if it's not about testing, what's it about?
It's about figuring out what you are trying to do before you run off half-cocked to try to do it.
You write a specification that nails down a small aspect of behaviour in a concise, unambiguous, and executable form.
It's that simple. Does that mean you write tests? No. It means you write specifications of what your code will have to do.
It means you specify the behaviour of your code ahead of time. But not far ahead of time.
In fact, just before you write the code is best because that's when you have as much information at hand as you will up to that point.
Like well done TDD, you work in tiny increments... specifying one small aspect of behaviour at a time, then implementing it.
When you realize that it's all about specifying behaviour and not writing tests, your point of view shifts.
Suddenly the idea of having a Test class for each of your production classes is ridiculously limiting.
And the thought of testing each of your methods with its own test method (in a 1-1 relationship) will be laughable.
如果關鍵點不是測試,那是什么呢?
關鍵是在你馬上就要做一件事之前指出你到底要做什么。你寫了一份說明,詳細到每一個細節的行為,簡明、無歧義、可執行。
這如此簡單。但那并不意味著你寫了tests,你只是寫了你的代碼的功能說明書。這意味著你在寫代碼前詳細分析了代碼的行為。實際上,
等到你馬上就要寫代碼時再去做這件事最好,因為這時你才能掌握關于這件事最詳盡的信息。就像做的很好的TDD,你只需要多做一點點工作就OK。
一次分析清楚所有行為細小的方面,然后實現它。
當你意識到問題的關鍵是分析行為(specifying behaviour)而不是寫tests,你的觀念發生了變化。突然,每個類對應一個測試類的主意狹隘的可笑。
對你的每一個方法都用相對應的test method(自己的方法和測試腳本的方法數量一比一)去測試?這是個笑話。
?---Dave Astels
?
行為驅動開發(BDD)的關注點是軟件開發過程中的語言和交互。BDD的開發者用他們自己的語言和領域驅動設計(Domain-Driven Design)的普遍語言相結合,來描述代碼的行為和目的。這使得開發者關注代碼的目的,而不是技術細節,最小化在代碼編程語言和領域設計專家(domain experts)所說的領域語言之間的差異。
PHPUnit_Extensions_Story_TestCase類添加了一個story framework,便于“領域特定語言”(Domain-Specific Language,DSL)為行為驅動開發做定義。
在一個scenario里,given(),when(),then()各自都是一個步驟。and()類似于前置步驟。下面的方法在PHPUnit_Extensions_Story_TestCase中做了抽象聲明,
需要實現他們:
??? * runGiven(&$world, $action, $arguments)
????? ...
??? * runWhen(&$world, $action, $arguments)
????? ...
??? * runThen(&$world, $action, $arguments)
????? ...
保齡球游戲例子
這里我們看看一個類,計算保齡球游戲的分數。規則如下:
??? *游戲由10場組成
??? *每一場player有2次機會來打倒10個瓶
??? *每一場的分數=擊倒的瓶子數 + strikes的bonus + spares的bonus
??? *spare是指player在2次拋球中擊倒全部10個瓶子。
???? 這一場的bonus就是下一次ROLL時擊倒的瓶子數。
??? *strike是指player第一次就擊倒全部10個瓶子。
???? 這一場的bonus就是下兩次ROLL時擊倒的瓶子數。
下面看看這些規則怎么表述
代碼??1<?php
??2require_once?'PHPUnit/Extensions/Story/TestCase.php';
??3require_once?'BowlingGame.php';
??4?
??5class?BowlingGameSpec?extends?PHPUnit_Extensions_Story_TestCase
??6{
??7????/**
??8?????*?@scenario
??9?????*/
?10????public?function?scoreForGutterGameIs0()
?11????{
?12????????$this->given('New?game')
?13?????????????->then('Score?should?be',?0);
?14????}
?15?
?16????/**
?17?????*?@scenario
?18?????*/
?19????public?function?scoreForAllOnesIs20()
?20????{
?21????????$this->given('New?game')
?22?????????????->when('Player?rolls',?1)
?23?????????????->and('Player?rolls',?1)
?24?????????????->and('Player?rolls',?1)
?25?????????????->and('Player?rolls',?1)
?26?????????????->and('Player?rolls',?1)
?27?????????????->and('Player?rolls',?1)
?28?????????????->and('Player?rolls',?1)
?29?????????????->and('Player?rolls',?1)
?30?????????????->and('Player?rolls',?1)
?31?????????????->and('Player?rolls',?1)
?32?????????????->and('Player?rolls',?1)
?33?????????????->and('Player?rolls',?1)
?34?????????????->and('Player?rolls',?1)
?35?????????????->and('Player?rolls',?1)
?36?????????????->and('Player?rolls',?1)
?37?????????????->and('Player?rolls',?1)
?38?????????????->and('Player?rolls',?1)
?39?????????????->and('Player?rolls',?1)
?40?????????????->and('Player?rolls',?1)
?41?????????????->and('Player?rolls',?1)
?42?????????????->then('Score?should?be',?20);
?43????}
?44?
?45????/**
?46?????*?@scenario
?47?????*/
?48????public?function?scoreForOneSpareAnd3Is16()
?49????{
?50????????$this->given('New?game')
?51?????????????->when('Player?rolls',?5)
?52?????????????->and('Player?rolls',?5)
?53?????????????->and('Player?rolls',?3)
?54?????????????->then('Score?should?be',?16);
?55????}
?56?
?57????/**
?58?????*?@scenario
?59?????*/
?60????public?function?scoreForOneStrikeAnd3And4Is24()
?61????{
?62????????$this->given('New?game')
?63?????????????->when('Player?rolls',?10)
?64?????????????->and('Player?rolls',?3)
?65?????????????->and('Player?rolls',?4)
?66?????????????->then('Score?should?be',?24);
?67????}
?68?
?69????/**
?70?????*?@scenario
?71?????*/
?72????public?function?scoreForPerfectGameIs300()
?73????{
?74????????$this->given('New?game')
?75?????????????->when('Player?rolls',?10)
?76?????????????->and('Player?rolls',?10)
?77?????????????->and('Player?rolls',?10)
?78?????????????->and('Player?rolls',?10)
?79?????????????->and('Player?rolls',?10)
?80?????????????->and('Player?rolls',?10)
?81?????????????->and('Player?rolls',?10)
?82?????????????->and('Player?rolls',?10)
?83?????????????->and('Player?rolls',?10)
?84?????????????->and('Player?rolls',?10)
?85?????????????->and('Player?rolls',?10)
?86?????????????->and('Player?rolls',?10)
?87?????????????->then('Score?should?be',?300);
?88????}
?89?
?90????public?function?runGiven(&$world,?$action,?$arguments)
?91????{
?92????????switch($action)?{
?93????????????case?'New?game':?{
?94????????????????$world['game']??=?new?BowlingGame;
?95????????????????$world['rolls']?=?0;
?96????????????}
?97????????????break;
?98?
?99????????????default:?{
100????????????????return?$this->notImplemented($action);
101????????????}
102????????}
103????}
104?
105????public?function?runWhen(&$world,?$action,?$arguments)
106????{
107????????switch($action)?{
108????????????case?'Player?rolls':?{
109????????????????$world['game']->roll($arguments[0]);
110????????????????$world['rolls']++;
111????????????}
112????????????break;
113?
114????????????default:?{
115????????????????return?$this->notImplemented($action);
116????????????}
117????????}
118????}
119?
120????public?function?runThen(&$world,?$action,?$arguments)
121????{
122????????switch($action)?{
123????????????case?'Score?should?be':?{
124????????????????for?($i?=?$world['rolls'];?$i?<?20;?$i++)?{
125????????????????????$world['game']->roll(0);
126????????????????}
127?
128????????????????$this->assertEquals($arguments[0],?$world['game']->score());
129????????????}
130????????????break;
131?
132????????????default:?{
133????????????????return?$this->notImplemented($action);
134????????????}
135????????}
136????}
137}
138?>
phpunit --story BowlingGameSpec
PHPUnit 3.4.2 by Sebastian Bergmann.
BowlingGameSpec
?[x] Score for gutter game is 0
?? Given New game
??? Then Score should be 0
?[x] Score for all ones is 20
?? Given New game
??? When Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
???? and Player rolls 1
??? Then Score should be 20
?[x] Score for one spare and 3 is 16
?? Given New game
??? When Player rolls 5
???? and Player rolls 5
???? and Player rolls 3
??? Then Score should be 16
?[x] Score for one strike and 3 and 4 is 24
?? Given New game
??? When Player rolls 10
???? and Player rolls 3
???? and Player rolls 4
??? Then Score should be 24
?[x] Score for perfect game is 300
?? Given New game
??? When Player rolls 10
???? and Player rolls 10
???? and Player rolls 10
???? and Player rolls 10
???? and Player rolls 10
???? and Player rolls 10
???? and Player rolls 10
???? and Player rolls 10
???? and Player rolls 10
???? and Player rolls 10
???? and Player rolls 10
???? and Player rolls 10
??? Then Score should be 300
Scenarios: 5, Failed: 0, Skipped: 0, Incomplete: 0.
轉載于:https://www.cnblogs.com/awaken/archive/2009/11/27/1612078.html
總結
以上是生活随笔為你收集整理的[PHP]用PHPUnit进行行为驱动开发(Behaviour-Driven Development)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 清除vs2005起始页最近打开项目
- 下一篇: 全屏广告代码