我正在我班上测试一个做日期检查的方法。问题是该方法取决于今天的日期(每天都在变化),这使得这很难测试。我如何模仿今天的日期,以便我的测试明天仍然通过?
答案 0 :(得分:8)
我对PHP一无所知,但在Java和C#中我会传递一些描述的“时钟” - 不是今天的日期本身,而是一个你可以询问当前日期的对象/时间。然后在单元测试中,您可以传入一个对象,该对象可以提供您想要的任何日期 - 包括一个硬编码到测试中的日期。
这也适用于PHP吗?
答案 1 :(得分:6)
如果您不想传递保留外部接口的日期,那么最好使用“seam”来提供日期:
class MyClass {
public function toBeTested() {
$theDate = $this->getDate();
...
}
protected function getDate() {
return date();
}
}
一般情况下,这个课程正常。 然后,在单元测试中,不是测试MyClass,而是使用覆盖getDate()函数的内部类扩展MyClass:
class MyTest extends phpunittestcase (sorry, writing this freeform, syntax is not exact!!) {
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()),并返回您要用于此特定测试的日期。
再次,抱歉,如果有一些令人震惊的语法错误,这是徒手写的。
答案 2 :(得分:4)
虽然Jon的回答是“正确的方法”,但另一个选择是使用runkit extension暂时将date()
和/或time()
函数替换为返回固定值的函数测试。
runkit.internal_override
中设置php.ini
,以便重命名内置函数。runkit_function_rename
重命名原始函数。这里有一些完全未经测试的代码可以帮助解决这个问题:
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()
方法中使用这些方法,以确保不会干扰后续的其他测试。
答案 3 :(得分:3)
我知道你不想把它作为一个参数传递。但也许你可以重新考虑一下......
当从外部作为参数传递时,日期不是一个无关紧要的技术细节,而是一个重要的功能规则。你不需要以下任何一种吗?
答案 4 :(得分:0)
大卫说,我无法重命名两次,所以我得到了它:
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');
}