我正在尝试使用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'
那么,我们应该做些什么来使这项工作?作为一个稍微相关的旁边,我们也无法弄清楚如何使全局变量适用于对象(我们有一个会话对象和一个数据库对象,我不知道为什么 - 我是一个实习生,这是在我来之前很久就编码了。
答案 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或falseP.S.S :提供的代码可能有拼写错误,我还没有运行它...
<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
)
或者您可以自己创建(取决于项目的文件结构)。
这样您就不需要require
或require_once
来加载需要测试的类