【发布时间】:2016-05-07 11:12:32
【问题描述】:
我正在尝试使用 PHPUnit 编写一组单元测试(DISCALIMER:这是我第一个尝试使用单元测试来提高代码质量的项目)。
我目前有一个 ConnectionManager 类,它管理与 MySQL 数据库的连接。这个类有两个成员函数:
GetDBSetLinks 和 ConnectWithMysqli。
GetDBSetLinks 是一个函数,它接收多个 mysql 数据库的连接信息数组(每个元素包含主机名、用户名等以及其他一些信息),并将此信息传递给 ConnectWithMysqli。
ConnectWithMySqli() 计算程序应使用mysqli_connect() 函数的哪个重载来连接 MySQL 数据库,然后使用传入的参数调用该重载。
当我使用我的单元测试将错误的连接信息(例如错误的密码)传递给GetDBSetLinks() 时,错误的信息得到正确处理,使其按预期传递给ConnectWithMySqli 函数。当不良信息命中mysqli_connect()时,函数失败并触发预期的
mysql_connect(): Access denied for user 'root'@'192.168.1.113' (using password:YES)" 错误。
问题是这也会终止ConnectWithMySqli() 的执行,因此ConnectWithMysqli() 将无法完成并返回我尝试测试的变量。
我想做的是保持程序运行但触发可以处理的异常。
问题是我刚开始使用try-catch,我不确定最好的方法。有人有什么想法吗?
Connection.php
<?php
class FailedConnection extends Exception{}
class ConnectionManager {
//FUNCTION: Gets List of Database Links for given database set----------------//
static public function GetDBSetLinks($CurrentDBSet){
$DatabaseLinkList = array();
foreach ($CurrentDBSet as $DatabaseInfoString){
//Split the Database info string by commas. The input string found in the
//configuration file is a single string containing all of the parameters
//needed to connect to the SQL database. The statement below takes this string
//and converts it into three separate variables, so that they can be passed into mysqli_connect()
$SplitDBInfo = preg_split('/,/', $DatabaseInfoString);
//Initialize a variable that serves as an iterator. This variable also holds
//the number of arguments that were found in the config fie.
$NumArgs = 0;
//Initialize other variables necessary to connect to the current database.
$DatabaseID = "NULL";
$HostName = "NULL";
$dbUsername = "NULL";
$dbPassword = "NULL";
$DatabaseName = "NULL"; //NOTE: Database name in the config file should exactly match the name of the database on the server.
$PortNumber = "NULL";
$Socket = "NULL";
//Cycle through the individual params now stored in SplitDBInfo, (1.) count
//them, then (2.) assign them to the appropriate variable to pass into mysqli_connect()
foreach ($SplitDBInfo as $Parameter){
$NumArgs ++; //(1.)
switch ($NumArgs) { //(2.)
case 1:
$DatabaseID = $Parameter;
break;
case 2:
$HostName = $Parameter;
break;
case 3:
$dbUsername = $Parameter;
break;
case 4:
$dbPassword = $Parameter;
break;
case 5:
$DatabaseName = $Parameter;
break;
case 6:
$PortNumber = $Parameter;
break;
case 7:
$Socket = $Parameter;
break;
default:
break;
}
//print $Parameter . "<br>"; //DEBUG
}
print '<br>' ."NumArgs: " . ($NumArgs) . '<br>'; //DEBUG ONLY
print "Number of Function Arguments: " . ($NumArgs -1) . '<br>'; //DEBUG ONLY;
echo "Connecting to Database '" . $DatabaseID . "' at hostname " . $HostName ."." . '<br>';
$link = self::ConnectWithMysqli($NumArgs, $HostName, $dbUsername, $dbPassword, $DatabaseName, $PortNumber, $Socket);
//If our link to the database is not successful, escape this sequence and do not put the link in our list of linked databases.
if (!$link){
echo "No Successful link to '" . $DatabaseID . "' at hostname " . $HostName .".";
echo '<br>';
}
//Otherwise, our link should be good, and we should add it to our list of database links.
else{
echo "Connection to Database '" . $DatabaseID . "' at hostname " . $HostName ." was successful.";
echo '<br>';
array_push($DatabaseLinkList, $link);
}
}
//After we finish iterating to generate a list of viable links, we can use these
//links to perform database operations.
return $DatabaseLinkList;
}
function ConnectWithMysqli($NumArgs,$HostName, $dbUsername, $dbPassword, $DatabaseName, $PortNumber, $Socket){
switch($NumArgs) {
case 2:
$link = mysqli_connect($HostName);
//could not connect
break;
case 3:
$link = mysqli_connect($HostName,$dbUsername);
break;
case 4:
$link = mysql_connect($HostName,$dbUsername,$dbPassword);
//$link = mysqli_connect($HostName,$dbUsername,$dbPassword);
break;
case 5:
print ($DatabaseName);
$link = mysqli_connect($HostName,$dbUsername,$dbPassword,$DatabaseName);
break;
case 6:
$link = mysqli_connect($HostName, $dbUsername, $dbPassword, $DatabaseName, $PortNumber, $Socket);
break;
default:
throw new FailedConnection;
}
try{
if(!$link){
throw new FailedConnection;
}
}
catch(FailedConnection $e){
return "Null";
}
return $link;
}
ConnectionModuleTest.php
<?php
require_once 'C:\Users\bsnider\Documents\BrandonDepot\SourceControl\git\repos\GLS_DBSearchProject\Connection.php';
class ConnectionModuleTest extends PHPUnit_Framework_TestCase{
public function setUp(){}
public function tearDown(){}
public function testDataGetDBSetLinks_GoodConnection(){
$ConnectionManager = new ConnectionManager;
//Valid Connection Parameters
$DBSet = array('MainDatabase,192.168.1.41,root,colt45', 'MainDatabase,192.168.1.41,root,colt45');
$Result = $ConnectionManager->GetDBSetLinks($DBSet); //$Result
$this->assertNotEmpty($Result);
}
public function testDataGetDBSetLinks_BadHostName(){
$ConnectionManager = new ConnectionManager;
//Invalid Connection Parameters
$DBSet = array('MainDatabase,192.168.1.20,root,colt45', 'MainDatabase,192.168.1.20,root,colt45');
$Result = $ConnectionManager->GetDBSetLinks($DBSet); //$Result
$this->assertEmpty($Result);
}
public function testDataGetDBSetLinks_BadPassword(){
$ConnectionManager = new ConnectionManager;
//Invalid Connection Parameters
$DBSet = array('MainDatabase,192.168.1.41,root,badpassword', 'MainDatabase,192.168.1.41,root,badpassword');
$Result = $ConnectionManager->GetDBSetLinks($DBSet); //$Result
$this->assertEmpty($Result);
}
public function testConnectWithMysqli(){
}
}
【问题讨论】:
-
最好将代码内联粘贴到您的问题中,即使它很长
-
单独测试 ConnectionManager 的错误处理。不要在其他用例的测试中测试 ConnectionManager
-
我认为您可能正在重新发明方轮。你为什么不使用或分叉其中一个库:例如packagist.org/search/?q=mysqli Like github.com/joshcam/PHP-MySQLi-Database-Class?
-
@Machavity 感谢您告诉我。我不经常使用 SxE。下次我一定会这样做。
-
@greg0ire 我不太确定我看到你的链接对我有什么好处。我没有太多时间看它,但它看起来可以为我处理错误,这并不是我现在真正想要的。在重新发明轮子方面。是的,我正在做一点。作为学习练习。不过谢谢你的链接,我开始的时候不知道。
标签: php mysql unit-testing exception try-catch