顯示具有 unit test 標籤的文章。 顯示所有文章
顯示具有 unit test 標籤的文章。 顯示所有文章

星期五, 6月 09, 2017

讓Stub跑原本的Code

本來Stubbing寫好好的,遇到要call stub裡未stubbing的method
一時還不知道怎麼寫,因為會遇到undefined mock function
原來直接用getMockBuilder就可以了
class aaa {
  public function test1(){return true;}
  public function test2(){return true;}
}

class StubTest extends PHPUnit_Framework_TestCase
{
  public function testStub()
  {
      $stub = $this->getMockBuilder('aaa')
        ->setMethods(array('test1'))
        ->getMock();

      $stub->expects($this->any())
        ->method('test1')
        ->will($this->returnValue(false));

        $this->assertFalse($stub->test1());
        $this->assertTrue($stub->test2());
  }
}

加上Namespace後,getMockBuilder裡的class,要加完整的namepspace才會真的取到, 不然會做個假的(test2會是undefined function)

星期日, 8月 31, 2014

Bowling Game Kata

看了Uncle Bob的建議,每天想來練一下Kata
而Uncle Bob又力推Bowling Game,所以原本想拿來當kata練一下不同的語言

沒想到實做之後,才發現這是個滿棒的kata
邏輯不會太難,但可能寫成超複雜的,滿多重構的行為,而且很適合當TDD的教材
把所有的team member都抓來練習一下

以下整理最近帶team member的心得
  • Refactoring (clean code)
    • 變數、method的命名
      刻意讓team member命名滾球、局數
      最後讓大家猜別人命名的意思
      最後讓大家直接用保齡球的術語roll, frame
      clean code: 不懂時,直接請domain expert命名,至少以後domain expert能夠說出這是什麼
    • redundant code
      去除重覆的程式
    • decompose condition
      讓程式變的更加clean, isSpare,isStrike,getSpareBonus那段
    • 隱藏細節
      上一段的延伸,有些team member把整段getSpareBonus做成calSpareBonus
      感覺上沒什麼差,但在看code感覺差很多
      • calSpareBonus
        這個function叫做score(算總分),因此這function最重要的事就是"算分數"
        但這裡把算分的邏輯隱藏了,因此未來看code的人,不易注意到score被其他function異動了
        int score = 0;//成員變數 - 總分 
        public int score(){
            //略
            if (isSpare())
                calSpareBonus(); 
            //略
        }
      • getSpareBonus
        關於score的異動,能夠清楚掌握
        而Spare的Bonus算法在這不重要,因此隱藏起來
        讓程式更容易閱讀
        public int score(){
            int score = 0;//總分
            //略
            if (isSpare())
                score += getSpareBonus(); 
            //略
        }
  • Pair-Programming
    自己開發會有盲點,跟幾個同事練習的過程中
  • 在算跨局的輯邏會想的滿複雜的,但partner會參與討論 也許沒能討論出更好、更簡單的解法,但至少那段神邏輯有另一個人"看的懂"
  • TDD
    只滿足目前的需求即可
    開發上,大家容易被分數算法綁住,因此一開始想把邏輯寫對
    但這不太容易,因為算法還得考慮Spare, Strike,因此一次要把邏輯寫出來有點難
    寫完,你也不會寫test case了,因為已經寫完繳卷了

    這點最適合TDD指的只滿足目前的需求即可
    先寫個最簡單的算法驗證,再來spare,再來strike,一個個拼出完整的邏輯
    也許整個寫法得翻掉重寫,但令人放心的是test case已經寫好了
    所以可以放心重寫

    雖然一直說TDD很棒,但沒實際體會過,大家只會覺得很難達成
    實際經歷好幾次的大改結構,但重新測試的時間,卻只是一瞬間
    大家就能體會TDD好處

回想其實好久以前就看過這Bowling Game的練習(很多對話那個)
不過就只有用"看"的,沒有實際寫過,身體力行的體驗果然不一樣
大家也來kata一下

p.s. 不過我以為這保齡球算法的方法大家應該都瞭解
沒想到大家都忘了... 話說上次打應該也是5年前了...

更多的Kata題目

星期日, 7月 27, 2014

如何寫unit test

以前覺得unit test不就寫test case
想到啥,就寫啥,沒有目標的亂寫
記得以前連搬檔案都寫了一個case來測
最近領悟了點東西,趕緊來整理一下

  • 測試資料
    寫test case最麻煩的地方在準備測試資料
    由於資料大多存取DB,因此得準備一個測試DB
    但資料被改後,還得再倒回去,否則test case會fail
    以前都用dump,再整個倒回去
    開發上還挺累人的

    個人測試還好,多人用同一個測試DB,就會互相蓋DB
    難道要一人一DB嗎... 這提出申請,一定被上頭打槍...

    後來才瞭解,這不是unit test
    這已經是integration test(接DB)
    unit test應該在幾秒內跑完才叫unit test
  • 利用Mock & Stub模擬測試資料
    後來就利用這做法,避免接DB,及外部API的動作
    說方便... 是比接DB方便... 但也還好...還是得寫一堆code,只為了準備測試資料
    想利用TDD寫好unit test,還是挺花時間的
    要說服其他人用,力道上還是不夠
  • 測邏輯就好
    直到前陣子,Kent Beck, Martin Fowler及DHH在討論「 IS TDD DEAD
    DHH在說實務上用TDD不可行,當然是被兩位大師訓了一頓...
    不過影響最深刻的是Martin Fowler說他幾乎沒在寫Mock

    實在太令人驚訝了...居然沒在寫mock.....
    很想實際看一下些大師怎麼寫的...

    雖然還是不知道大師怎麼寫的
    不過自己重新領悟unit test就是在測試邏輯
    即然是測邏輯.... 那.... 就把邏輯這段再抽成一個function獨立出來就容易測了
    YA~~
    現有終於可以輕鬆的寫test case (泣)
當然~ 難免有些地方還是不好寫unit test
大師也說... 不好寫的就不要刻意寫,工具有他的極限
不要硬寫,而搞死自己 <= 好吧 這句是我自己將來為了辯解沒寫unit test的藉口

星期二, 10月 22, 2013

mock 寫法


  • Quick start
    $stub = $this->getMockBuilder('modelAbc')
                           ->setMethods(array('findFirst'))
                           ->getMock();
    
    $stub->expects($this->any())
             ->method('findFirst')
             ->will($this->returnValue(null));
  • 靜態寫法 (PHPUnit 3.9後就不支援static寫法了)
    $stub = $this->getMockClass(
                'modelAbc',
                array('findHistory')
            ) ;
    
    $stub::staticExpects($this->any())
                ->method('findHistory')
                ->will($this->returnValue($result));

method執行次數

Example:
$stub->expects($this->once())
->method('doSomething');

$this->once(); 只會被執行一次
$this->exactly(3); //只能3次
$this->any(); //不管幾次

method 回傳值

  • 回傳固定值
    語法:$this->returnValue()
    Example:
    $stub->expects($this->any())
    ->method('doSomething')
    ->will($this->returnValue("Yes, sir!");
  • 隨機回傳不同值
    語法:
  • 依參數給回傳不同值
    語法:$this->returnValueMap(array(param1, ..., paramN, returnValue)
    Example:
    $stub->expects($this->any())
        ->method('doSomething')
        ->will(
            $this->returnValueMap(
                array(
                array('a', 'b', 'c', 'd'),
                array('e', 'f', 'g', 'h'))
            )
        )
    );
    $this->assertEquals('d', $stub->doSomething('a', 'b', 'c')); 
    $this->assertEquals('h', $stub->doSomething('e', 'f', 'g'));

Issue

  • Phalcon\Mvc\Model\Exception: The method "__phpunit_getInvocationMocker" doesn't exist on model
    • Solution
      一般因為有namespace,只要補上完整的namespace即可
      $stub = $this->getMockBuilder('namespace_path\modelAbc');

Reference