PHPUnit和定义的变量

时间:2016-07-08 21:19:03

标签: php phpunit global-variables static-variables

我正在尝试使用PHPUnit处理一些遗留代码。我的想法是,我需要了解将来使用PHPUnit对公司是否可行或可行。我遇到的一个问题是我们使用了很多define()函数来设置我们的数据库信息。具体来说,我们使用'DB_HOST'替换我们数据库的名称。我注意到PHPUnit不喜欢这种让一切变得均匀的方法。这是相关代码+错误。

require_once("./includes/class.casestatusprovider.php");
require_once("./config/config_db.php");
require_once("./config/config_tables.php");

class TestCaseStatusProvider extends TestCase
{

    public function setUp()
    {
        $csp = new CaseStatusProvider();
    }

    /**
      * @covers CaseStatusProvider::insert
      */
    public function testInsert_csrIdActive()
    {
        require_once("./config/config_db.php");
        require_once("./config/config_tables.php");
        $this->case_id=10;
        $this->csr_id=1;
        $this->assertNotFalse(insert($this->case_id, $this->csr_id));
    }
}

要测试的代码

abstract class CaseStatusProvider
 {
    public static function insert($case_id, $csr_id)
    {
        global $DBH;
        global $session;

        if($session->isLoggedIn())
        {
            try{

                $query = "INSERT into ".DB_NAME.".".TBL_CASE_STATUS." (case_id, csr_id, created_by, effective_date, isPast) Values (?, ?, ?, ?, ?) ";
                $data = array($case_id, $csr_id, $session->user_id, time(), 0);
                $STH = $DBH->prepare($query);
                $STH->execute($data);
                $fetched = $STH->fetch();

                return $fetched;

            }catch(PDOException $e) { 
                echo $e->getMessage();
                return false;   
            }
        } 

        return false;           
    }

ERROR

 Could not connect: Unknown MySQL server host 'DB_HOST' 

那么,我们应该做些什么来使这项工作?作为一个稍微相关的旁边,我们也无法弄清楚如何使全局变量适用于对象(我们有一个会话对象和一个数据库对象,我不知道为什么 - 我是一个实习生,这是在我来之前很久就编码了。

1 个答案:

答案 0 :(得分:1)

我想我会回答这个问题因为它更容易。

首先,你应该知道这个(评论) - 类需要像下面一样进行修改(为了模拟行为) - 或者使用setter但是在构造中似乎更好,因为它的状态取决于它们:

abstract class CaseStatusProvider
{

    private $database;

    private $session;

    public funtion __construct($database, $session) {
        $this->database = $database;
        $this->session = $session;
    }

    public static function insert($case_id, $csr_id)
    {
        if($session->isLoggedIn())
        {
            try{

                $query = "INSERT into ".DB_NAME.".".TBL_CASE_STATUS." (case_id, csr_id, created_by, effective_date, isPast) Values (?, ?, ?, ?, ?) ";
                $data = array($case_id, $csr_id, $this->session->user_id, time(), 0);
                $STH = $this->database->prepare($query);
                $STH->execute($data);
                $fetched = $STH->fetch();
                return $fetched;
            }catch(PDOException $e) { 
                echo $e->getMessage();
                return false;   
            }
        } 
        return false;           
    }
}

class classToBeTested extends CaseStatusProvider
{

}

我们的测试用例应该是这样的: 请注意,使用DI时我们可以强制给定类别的优点。

class TestCaseStatusProvider extends TestCase
{

    private $session;

    private $database;
    //we need to mock the behavior of the statement in order to retrieve different data sets
    //according to our test cases
    private $pdoStatement;

    private $databaseClass;

    public function setUp()
    {
        //we start by mocking the database
        $this->database = $this->getMock('mysqli'); // I'm guessing mysqli

        //mock the statement in order to controll the fetch method later
        $this->pdoStatement = this->getMock('PDOStatement');
        $this->pdoStatement->method('execute')
            ->willReturn(null); // we'll just mock the fetch method in our test cases

        $this->database->method('prepare')
            ->willReturn($pdoStatement); // we mock the retrieval of a PDOStatement

        //then we mock the session
        $this->session = $this->getMock('YourSessionClass');
        //since you are accessing user_id from the class you should mock it
        $this->session->user_id = 20;

        $this->databaseClass = new classToBeTested( $this->session);
    }


    public function testInsertOk()
    {
        //We mock that the user is logged in
        $this->session->method('isLoggedIn')
             ->willReturn(true);
        $this->pdoStatement->method('fetch')
            ->willReturn(array()); // we'll just mock the fetch method, no actual data needed here
        $this->assertNotFalse($this->databaseClass->insert(1, 1));
    }

    public function testInsertKo1()
    {
        //We mock that the user is logged in
        $this->session->method('isLoggedIn')
             ->willReturn(false);
        //no need to mock the fetch method because it will not be executed
        $this->assertFalse($this->databaseClass->insert(1, 1));
    }

    public function testInsertKo2()
    {
        //We mock that the user is logged in
        $this->session->method('isLoggedIn')
             ->willReturn(true);
        $this->pdoStatement->method('fetch')
            ->will($this->throwException(new PDOException)); //mock exception on insert
        $this->assertFalse($this->databaseClass->insert(1, 1));
    }
}

P.S :尝试更改课程以采用[单一责任原则1

简而言之,插入方法应该只插入(不检查用户是否已记录 - 这应该在另一个具有CaseStatusProvider实例的类中完成,该类检查是否记录了用户)并返回如果错误(或抛出异常)

,则为true或false

P.S.S :提供的代码可能有拼写错误,我还没有运行它...

配置(link):

<phpunit
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.5/phpunit.xsd"

         <!--bootstrap="/path/to/bootstrap.php"--> 
         [...]
         >
  <!-- ... -->
</phpunit>

您可以传递一个引导文件来访问项目中的所有类(如果您使用的是构建它的框架(例如:Symfony使bootstrap.cache.php

或者您可以自己创建(取决于项目的文件结构)。

这样您就不需要requirerequire_once来加载需要测试的类