开发者

Overide parent function in stub

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:

/**
 * @expectedE开发者_Python百科xception 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?


I'm trying to test a protected method [...]

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

So: Just because the testing of protected and private attributes and methods is possible does not mean that this is a "good thing".

and: Best practices to test protected methods with PHPUnit - on abstract classes

What this post also mentions is to just use

$method = new ReflectionMethod(
    'Foo', 'doSomethingPrivate'
);
$method->setAccessible(TRUE);

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 not parent::localConnect because parent:: is only for calling the same method of the parent class. (Doesn't matter much, just confusing, for me at least).


This may be a stupid question, but did you override DbConnectStub::getInstance for it to return a Stub instance ?

class DBConnectStub extends DBconnect{
 public static function getInstance ()
 {
    //whatever process to create the instance (and not the parent method call that will return a DBConnect instance)
 } 

 public function callLocalConnect($localConfig){
    parent::localConnect($localConfig);
 }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜