2013-04-04 126 views
3

我按照本教程:http://jtreminio.com/2013/03/unit-testing-tutorial-part-5-mock-methods-and-overriding-constructors/。学习如何运作PHPUnit的好教程。软断言和模拟方法测试失败

但我无法理解,因为测试未通过。

失败是:

Method was expected to be called 1 times, actually called 0 times. 

在这部分代码:

 $badCode->expects($this->once()) 
      ->method('checkPassword') 
      ->with($password); 

但因为下软断言checkPassword方法内运行,并通过测试,这是不可能的。

 $badCode->expects($this->once()) 
      ->method('callExit'); 

它失败了,因为是一个模拟方法,行为是不同的?或者代码错了?

为了便于理解,附上所有文件,这是一个小例子。

控制台

PHPUnit 3.7.18 by Sebastian Bergmann. 

FYOU SHALL NOT PASS............ 

Time: 0 seconds, Memory: 6.00Mb 

There was 1 failure: 

1) phpUnitTutorial\Test\BadCodeTest::testAuthorizeExitsWhenPasswordNotSet 
Expectation failed for method name is equal to <string:checkPassword> when invoked 1 time(s). 
Method was expected to be called 1 times, actually called 0 times. 


FAILURES! 
Tests: 13, Assertions: 14, Failures: 1. 

BadCode.php

<?php 

namespace phpUnitTutorial; 

class BadCode 
{ 
    protected $user; 

    public function __construct(array $user) 
    { 
     $this->user = $user; 
    } 

    public function authorize($password) 
    { 
     if ($this->checkPassword($password)) { 
      return true; 
     } 

     return false; 
    } 

    protected function checkPassword($password) 
    { 
     if (empty($user['password']) || $user['password'] !== $password) { 
      echo 'YOU SHALL NOT PASS'; 
      $this->callExit(); 
     } 

     return true; 
    } 

    protected function callExit() 
    { 
     exit; 
    } 
} 

BadCodeTest.php

<?php 

namespace phpUnitTutorial\Test; 

class BadCodeTest extends \PHPUnit_Framework_TestCase 
{ 
    public function testAuthorizeExitsWhenPasswordNotSet() 
    { 
     $user = array('username' => 'jtreminio'); 
     $password = 'foo'; 

     $badCode = $this->getMockBuilder('phpUnitTutorial\BadCode') 
      ->setConstructorArgs(array($user)) 
      ->setMethods(array('callExit')) 
      ->getMock(); 

     $badCode->expects($this->once()) 
      ->method('checkPassword') 
      ->with($password); 

     $badCode->expects($this->once()) 
      ->method('callExit'); 

     $this->expectOutputString('YOU SHALL NOT PASS'); 

     $badCode->authorize($password); 
    } 
} 

有人能帮助我吗?谢谢!

更新

的博客更新了解决方案本教程的作者。 不能对模拟方法做任何断言,只有存根。

BadCode.php

<?php 

namespace phpUnitTutorial; 

class BadCode 
{ 
    protected $user; 

    public function __construct(array $user) 
    { 
     $this->user = $user; 
    } 

    public function authorize($password) 
    { 
     if ($this->checkPassword($password)) { 
      return true; 
     } 

     return false; 
    } 

    protected function checkPassword($password) 
    { 
     if (empty($this->user['password']) || $this->user['password'] !== $password) { 
      echo 'YOU SHALL NOT PASS'; 
      $this->callExit(); 
     } 

     return true; 
    } 

    protected function callExit() 
    { 
     exit; 
    } 
} 

BadCodeTest.php

<?php 

namespace phpUnitTutorial\Test; 

class BadCodeTest extends \PHPUnit_Framework_TestCase 
{ 
    public function testAuthorizeExitsWhenPasswordNotSet() 
    { 
     $user = array('username' => 'jtreminio'); 
     $password = 'foo'; 

     $badCode = $this->getMockBuilder('phpUnitTutorial\BadCode') 
      ->setConstructorArgs(array($user)) 
      ->setMethods(array('callExit')) 

     $badCode->expects($this->once()) 
      ->method('callExit'); 

     $this->expectOutputString('YOU SHALL NOT PASS'); 

     $badCode->authorize($password); 
    } 
} 

回答

0

作者在这里 - 我欺骗了这部分,AppFog(我的主机)有免费帐户(我的)的问题,所以我现在无法更新它。

而且,是的,它应该是在$this->usercheckPassword()

+0

好吧,我等待解决方案! Muchas Gracias! – Sangar82 2013-04-04 19:48:58

+1

嘿@ Sangar82代码已经更新。抱歉的混乱! – 2013-04-04 19:57:27

+0

你已经删除了$ badCode-> expect($ this-> once()) - >方法('checkPassword') - > with($ password);但为什么?这似乎应该工作,但我不明白,因为在删除这些行之前测试失败 – Sangar82 2013-04-04 20:08:23

0

你缺少setMethods的方法:

->setMethods(array('callExit')) 

您需要添加checkPassword太多,如果你想检查它是否被调用。

+0

我认为这太(它可能是正确的),但例子仍然无法工作 – hek2mgl 2013-04-04 17:17:45

+1

这个例子是学习模拟和存根方法之间的差异。在这个例子中,checkPassword不是int setMethods,因为它是一个模拟方法,并且callExit一个存根方法 – Sangar82 2013-04-04 17:26:11

+1

@ Sangar82是的,你是对的。我已经学会了......感谢教程。现在我理解你的代码,它看起来没问题。你需要'callExit()'作为存根,否则会结束测试套件(使用exit)。将需要更深入的测试。你使用哪个PHPUnit版本?但是你应该做的一件事(尽管)它不直接属于这个问题:在'checkPassword()' – hek2mgl 2013-04-04 18:08:00