覆盖存根中的父函数
对于你们中的一些人来说,这可能是一件容易的事。我正在尝试在我拥有的小型数据库连接类上测试受保护的方法。
相关代码如下:
class DbConnect{
/**
* Connexion MSSQL local
*/
protected function localConnect($localconfig){
$connectionInfo = array("UID" => $localconfig->uid,
"PWD" =>$localconfig->pwd,
"Database"=> $localconfig->DB);
$this->localConnection = sqlsrv_connect($localconfig->serverName,
$connectionInfo);
if( $this->localConnection === false ){
$sql_error = sqlsrv_errors();
throw new DBException("Error in DB Connection.\r\n
SQL ERROR:" . $sql_error);
}
}
}
为了测试该方法,我有一个好主意(可能来自此处某处的帖子)来子类化并从那里调用。我在测试文件的底部创建了一个子类。我显然无法覆盖该方法对公共的可见性,因此决定在存根中采用另一种方法:声明一个调用父级受保护的 localConnect 方法的公共方法:
class DBConnectStub extends DBconnect{
public function callLocalConnect($localConfig){
parent::localConnect($localConfig);
}
}
我的测试现在看起来像这样:
/**
* @expectedException DBException
*/
public function test_localConnectError(){
$localconfig = (object) array ( 'serverName' => 'nohost',
'uid' => 'nouid',
'pwd' => 'noPwd',
'DB' => 'noDB'
);
$db = DbConnectStub::getInstance($localconfig, array());
$db->callLocalConnect($localConfig);
unset($db);
}
奇怪的部分,当我运行测试时,php 吐出:
致命错误:调用 C:\tirelinkCRMsync\test 中未定义的方法 DbConnect::callLocalConnect() \tirelinkCRMSync\DBConnectTest.php 第 82 行。
该对象已正确实例化,但为什么未定义该方法,肯定有一个细节让我困惑。这种方法有效还是有更好的方法?
This is probably an easy one for some of you. I'm trying to test a protected method on a small DB connection class I have.
Relevant code is as follows:
class DbConnect{
/**
* Connexion MSSQL local
*/
protected function localConnect($localconfig){
$connectionInfo = array("UID" => $localconfig->uid,
"PWD" =>$localconfig->pwd,
"Database"=> $localconfig->DB);
$this->localConnection = sqlsrv_connect($localconfig->serverName,
$connectionInfo);
if( $this->localConnection === false ){
$sql_error = sqlsrv_errors();
throw new DBException("Error in DB Connection.\r\n
SQL ERROR:" . $sql_error);
}
}
}
To test the method, I had the bright idea (probably from a post here somewhere) to subclass and call from there. I created a subclass, right at bottom of my test file. I obviously could not override the visibility of the method to public, so decided another approach in the stub: declare a public method that calls the parent's protected localConnect method:
class DBConnectStub extends DBconnect{
public function callLocalConnect($localConfig){
parent::localConnect($localConfig);
}
}
My test now looks like this:
/**
* @expectedException DBException
*/
public function test_localConnectError(){
$localconfig = (object) array ( 'serverName' => 'nohost',
'uid' => 'nouid',
'pwd' => 'noPwd',
'DB' => 'noDB'
);
$db = DbConnectStub::getInstance($localconfig, array());
$db->callLocalConnect($localConfig);
unset($db);
}
The weird part, when I run the test, php spits out:
Fatal error: Call to undefined method DbConnect::callLocalConnect() in C:\tirelinkCRMsync\test
\tirelinkCRMSync\DBConnectTest.php on line 82.
The object is properly instanciated, but why is the method not defined, surely there is a detail that has eluded me. Is this approach valid or is there a better way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不要
就这么简单。只是不要。受保护的方法不是类公共 API 的一部分,因此在尝试确保类正常工作时,不应假设它们的工作方式。
您应该能够在不调整测试的情况下更改代码(公共函数的实现)。这就是您的测试制作的目的,以便您可以更改代码并你确信它仍然有效。当您同时更改代码和测试时,您无法确定您的代码仍然像以前一样工作!
请参阅:
Sebastian Bergmann - 测试您的隐私.html
以及:
最佳使用 PHPUnit 测试受保护方法的实践 - 在抽象类上
这篇文章还提到,使用
Which 比为每个要测试的方法创建子类更容易。
迂腐的侧节点:
恕我直言,它应该是
$this->localConnect
而不是parent::localConnect
因为parent::仅用于调用相同 父类的方法。 (没什么大不了的,只是令人困惑,至少对我来说)。DON'T
It's as simple as that. Just don't. Protected methods are not part of the classes public API and therefore you should not make assumptions on how they work when trying to make sure your class works.
You should be able to change your code (implementation of your public functions) without adapting your tests. Thats what your tests are made for, so that you can change your code and you are sure that it still works. You can't be sure your code still works like before when you change your code and your tests at the same time!
See:
Sebastian Bergmann -Testing Your Privates.html
and:
Best practices to test protected methods with PHPUnit - on abstract classes
What this post also mentions is to just use
Which is easier than to create a subclass for every method you want to test.
Pedantic side node:
Imho it should be
$this->localConnect
and notparent::localConnect
because parent:: is only for calling the same method of the parent class. (Doesn't matter much, just confusing, for me at least).这可能是一个愚蠢的问题,但是您是否重写了 DbConnectStub::getInstance 以使其返回 Stub 实例?
This may be a stupid question, but did you override DbConnectStub::getInstance for it to return a Stub instance ?