如何使用phpunit测试调用抽象方法的具体方法
How to test a concrete method calling an abstract method with phpunit
我有一个带有具体方法的抽象 class。所以我想测试那些具体的方法。
这是我的摘要class:
abstract class File {
private $debug_filename_pattern = 'DELETE_ME_%s.debug';
private $filename;
private $filepath;
abstract public function buildFilename();
public function __construct($debug = false) {
$filename = $this->buildFilename();
if ($debug) {
$filename = sprintf($this->debug_filename_pattern, $filename);
}
$this->filename = $filename;
$this->buildFilepath();
}
private function buildFilepath() {
$this->filepath = ini_get('upload_tmp_dir') . DIRECTORY_SEPARATOR . $this->filename;
}
}
我阅读了 phpunit documentation 中关于测试摘要 classes 的部分,我想出了那个测试:
final class FileTest extends \PHPUnit_Framework_TestCase {
public function test() {
$stub = $this->getMockForAbstractClass('MyBundle\File', [true]);
$stub->expects($this->atLeastOnce())
->method('buildFilename')
->withAnyParameters()
->will($this->returnValue('test.log'));
$this->assertEquals('C:\xampp\tmp\DELETE_ME_test.log.debug', $stub->getFilePath());
}
}
但它不起作用。我总是断言 returns 它失败并显示此错误消息:
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'C:\xampp\tmp\DELETE_ME_test.log.debug'
+'C:\xampp\tmp\DELETE_ME_.debug'
我知道我的模拟对象已实例化,然后我为 buildFilename
方法添加了一个模拟。让我的测试总是失败。
有没有办法在实例化之前模拟我的抽象方法?我应该重构我的摘要 class 吗?
我认为您无法按照自己的方式设置模拟。 ->getMock()
时正在调用构造方法。那你就是在试图在事后设定期望。
一般来说,我发现当某些东西变得难以测试时(如本例),这表明设计存在问题。我认为你遇到的问题是在这种情况下你在构造函数中做的太多了。
您正在做各种繁重的工作来确定对象构造上的文件路径。为什么不更改它以便它在您调用 getFilePath
时发生。您的 class 最终会看起来像这样:
abstract class File {
private $debug_filename_pattern = 'DELETE_ME_%s.debug';
private $filename;
private $filepath;
protected $debug;
abstract public function buildFilename();
public function __construct($debug = false) {
$this->debug = $debug;
}
private function buildFilepath() {
$filename = $this->buildFilename();
if ($this->debug) {
$filename = sprintf($this->debug_filename_pattern, $filename);
}
$this->filename = $filename;
$this->filepath = ini_get('upload_tmp_dir') . DIRECTORY_SEPARATOR . $this->filename;
}
public function getFilePath() {
if(!this->filepath) {
$this->buildFilepath();
}
return $this->filepath;
}
}
现在在你的测试中,确保路径只构建一次,再添加一次你的断言。
final class FileTest extends \PHPUnit_Framework_TestCase {
public function test() {
$stub = $this->getMockForAbstractClass('MyBundle\File', [true]);
$stub->expects($this->once())
->method('buildFilename')
->withAnyParameters()
->will($this->returnValue('test.log'));
$this->assertEquals('C:\xampp\tmp\DELETE_ME_test.log.debug', $stub->getFilePath());
$this->assertEquals('C:\xampp\tmp\DELETE_ME_test.log.debug', $stub->getFilePath());
}
}
我有一个带有具体方法的抽象 class。所以我想测试那些具体的方法。
这是我的摘要class:
abstract class File {
private $debug_filename_pattern = 'DELETE_ME_%s.debug';
private $filename;
private $filepath;
abstract public function buildFilename();
public function __construct($debug = false) {
$filename = $this->buildFilename();
if ($debug) {
$filename = sprintf($this->debug_filename_pattern, $filename);
}
$this->filename = $filename;
$this->buildFilepath();
}
private function buildFilepath() {
$this->filepath = ini_get('upload_tmp_dir') . DIRECTORY_SEPARATOR . $this->filename;
}
}
我阅读了 phpunit documentation 中关于测试摘要 classes 的部分,我想出了那个测试:
final class FileTest extends \PHPUnit_Framework_TestCase {
public function test() {
$stub = $this->getMockForAbstractClass('MyBundle\File', [true]);
$stub->expects($this->atLeastOnce())
->method('buildFilename')
->withAnyParameters()
->will($this->returnValue('test.log'));
$this->assertEquals('C:\xampp\tmp\DELETE_ME_test.log.debug', $stub->getFilePath());
}
}
但它不起作用。我总是断言 returns 它失败并显示此错误消息:
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'C:\xampp\tmp\DELETE_ME_test.log.debug'
+'C:\xampp\tmp\DELETE_ME_.debug'
我知道我的模拟对象已实例化,然后我为 buildFilename
方法添加了一个模拟。让我的测试总是失败。
有没有办法在实例化之前模拟我的抽象方法?我应该重构我的摘要 class 吗?
我认为您无法按照自己的方式设置模拟。 ->getMock()
时正在调用构造方法。那你就是在试图在事后设定期望。
一般来说,我发现当某些东西变得难以测试时(如本例),这表明设计存在问题。我认为你遇到的问题是在这种情况下你在构造函数中做的太多了。
您正在做各种繁重的工作来确定对象构造上的文件路径。为什么不更改它以便它在您调用 getFilePath
时发生。您的 class 最终会看起来像这样:
abstract class File {
private $debug_filename_pattern = 'DELETE_ME_%s.debug';
private $filename;
private $filepath;
protected $debug;
abstract public function buildFilename();
public function __construct($debug = false) {
$this->debug = $debug;
}
private function buildFilepath() {
$filename = $this->buildFilename();
if ($this->debug) {
$filename = sprintf($this->debug_filename_pattern, $filename);
}
$this->filename = $filename;
$this->filepath = ini_get('upload_tmp_dir') . DIRECTORY_SEPARATOR . $this->filename;
}
public function getFilePath() {
if(!this->filepath) {
$this->buildFilepath();
}
return $this->filepath;
}
}
现在在你的测试中,确保路径只构建一次,再添加一次你的断言。
final class FileTest extends \PHPUnit_Framework_TestCase {
public function test() {
$stub = $this->getMockForAbstractClass('MyBundle\File', [true]);
$stub->expects($this->once())
->method('buildFilename')
->withAnyParameters()
->will($this->returnValue('test.log'));
$this->assertEquals('C:\xampp\tmp\DELETE_ME_test.log.debug', $stub->getFilePath());
$this->assertEquals('C:\xampp\tmp\DELETE_ME_test.log.debug', $stub->getFilePath());
}
}