Unit testing PHPUnit:如何嘲笑今天';如果不把它作为一个参数传递,它的日期是多少?
我正在我的类上测试一个方法,该方法执行一些日期检查。问题是该方法依赖于今天的日期(每天都在变化),这使得测试变得困难。我怎样才能模拟今天的日期,使我的测试明天仍能通过?我对PHP一无所知,但在Java和C中,我都会传入一个描述为“时钟”的东西——不是今天的日期本身,而是一个可以询问当前日期/时间的对象。然后在单元测试中,您可以传入一个对象,该对象可以给出您想要的任何日期,包括硬编码到测试中的日期 这在PHP中也适用吗?虽然Jon的答案是“正确的方法”,但另一个选择是使用临时替换Unit testing PHPUnit:如何嘲笑今天';如果不把它作为一个参数传递,它的日期是多少?,unit-testing,phpunit,Unit Testing,Phpunit,我正在我的类上测试一个方法,该方法执行一些日期检查。问题是该方法依赖于今天的日期(每天都在变化),这使得测试变得困难。我怎样才能模拟今天的日期,使我的测试明天仍能通过?我对PHP一无所知,但在Java和C中,我都会传入一个描述为“时钟”的东西——不是今天的日期本身,而是一个可以询问当前日期/时间的对象。然后在单元测试中,您可以传入一个对象,该对象可以给出您想要的任何日期,包括硬编码到测试中的日期 这在PHP中也适用吗?虽然Jon的答案是“正确的方法”,但另一个选择是使用临时替换date()和/或
date()
和/或time()
函数,这些函数为测试返回固定值
php.ini
中设置runkit.internal\u override
,以便可以重命名内置函数function mock_function($original, $mock) {
runkit_function_rename($original, $original . '_original');
runkit_function_rename($mock, $original);
}
function unmock_function($original, $mock) {
runkit_function_rename($original, $mock);
runkit_function_rename($original . '_original', $original);
}
您应该在
setUp()
和tearDown()
方法中使用这些方法,以确保不会干扰后续的其他测试。我知道您不想将其作为参数传入。但也许你可以重新考虑一下
当从外部作为参数传递时,日期不是无关紧要的技术细节,而是重要的功能规则。你不需要以下任何一项吗
- 尽管当前日期可以是常规用例,但该规则可能适用于其他日期。这样,您的代码将更加通用,并且可以在以后的用例中工作,无需修改。这经常发生在我身上
- 一些代码可以在算法中使用当前日期。因为计算机的速度不是无限的,几个会得到不同的瞬间。。。这在功能上合乎逻辑吗?或者使用相同的瞬间(例如,用户按下“点火”按钮的瞬间)会更准确吗?如果这些时间在您的数据库中都不同,即使它们对您的用户来说代表同一个瞬间,思考您以后如何在数据库中请求这些时间李>
class MyClass {
public function toBeTested() {
$theDate = $this->getDate();
...
}
protected function getDate() {
return date();
}
}
在一般情况下,这个类只能正常工作。
然后,在单元测试中,不是测试MyClass,而是使用覆盖getDate()函数的内部类扩展MyClass:
use PHPUnit\Framework\TestCase;
class MyTest extends TestCase {
static $testDate;
public function testToBeTested() {
//set the date to be used
MyTest::testDate = '1/2/2000';
$classUnderTest = new MyClassWithDate();
$this->assertEquals('expected', $classUnderTest->toBeTested());
}
}
//just pass back the expected date
class MyClassWithDate extends MyClass {
protected function getDate() {
return MyTest::testDate;
}
}
在这段代码中,您针对真实类的扩展进行测试,但是您的扩展重写了seam函数(getDate()),并返回您希望用于此特定测试的日期
再说一次,如果有一些严重的语法错误,很抱歉,这是徒手写的。我不能像David说的那样重命名两次,所以我得到了如下结果:
function mockDate()
{
runkit_function_rename('date', 'test_date_override');
runkit_function_add('date','$format=NULL,$timestamp=NULL,$locale=NULL', 'return DATEMOCK;');
}
function unmockDate()
{
runkit_function_remove('date');
runkit_function_rename('test_date_override', 'date');
}
问题是,该方法取决于今天的日期(每天都在变化),+1让我咯咯地笑了起来。可能是重复的是,不幸的是,这意味着将一个轻量级函数
date()
替换为一个必须在任何地方使用的对象。这是正确的方法,但是如果没有像Spring框架这样的好容器,那么会有很多工作要做。