PHP和测试驱动开发-日志类测试
我现在开始使用TDD。我做了一些测试来编写一个日志类 我怎么知道我是否在测试中涵盖了所有内容 我错过任何测试了吗?测试“testShouldWriteANewLogEntry”使用日期和时间,我测试对了吗 你对我的考试有什么建议吗 日志测试PHP和测试驱动开发-日志类测试,php,tdd,phpunit,logging,Php,Tdd,Phpunit,Logging,我现在开始使用TDD。我做了一些测试来编写一个日志类 我怎么知道我是否在测试中涵盖了所有内容 我错过任何测试了吗?测试“testShouldWriteANewLogEntry”使用日期和时间,我测试对了吗 你对我的考试有什么建议吗 日志测试 define('FILENAME', 'logs.txt'); class LogTest extends PHPUnit_Framework_TestCase { public function setUp() { if
define('FILENAME', 'logs.txt');
class LogTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
if (file_exists(FILENAME)) {
unlink(FILENAME);
}
}
public function testShouldCreateANewLogFile()
{
$log = new Log(FILENAME);
$this->assertFileExists(FILENAME);
}
public function testShouldWriteANewLogEntry()
{
$log = new Log(FILENAME);
$log->write('This is a log message');
$regExp = date('m/d/Y h:i:s a').' - This is a log message';
$regExp = str_replace('/', '\/', $regExp);
$this->assertRegExp('/^'.$regExp.'$/', file_get_contents(FILENAME));
}
public function testShouldWriteFiveLogEntries()
{
$log = new Log(FILENAME);
for ($i = 0; $i < 5; $i++) {
$log->write('#'.($i + 1).' message.');
}
$lines = count(file(FILENAME));
$this->assertEquals($lines, 5);
}
}
?>
我感谢你的帮助。这将是伟大的TDD新手。
谢谢。我突然想到一件事,你的第二次测试对时间很敏感。如果您的机器运行稍慢,测试可能会失败,因为完成测试所需的时间稍长。但是,您确实需要查看日志条目是否正确地输入了日期时间。为此,传入一个伪DateTime接口,将其与“获取时间问题”分开进行测试 也许是这样的:
interface DateRetriever {
public function getCurrentDate($format);
}
public function testShouldWriteANewLogEntry()
{
$log = new Log(FILENAME, new FakeDate());
$log->write('This is a log message');
$regExp = "2000-1-1".' - This is a log message';
$regExp = str_replace('/', '\/', $regExp);
$this->assertRegExp('/^'.$regExp.'$/', file_get_contents(FILENAME));
}
class RealDate implements DateRetriever {
public function getCurrentDate($format) {
return new DateTime()->format($format);
}
}
class FakeDate implements DateRetriever {
public function getCurrentDate($format) {
return new DateTime("2000-1-1");
}
}
然后是日志类:
public function __construct($file)
{
$this->_file = fopen($file, 'a');
}
public function write($message)
{
$dateTime = new DateTime();
$message = $dateTime->format('m/d/Y h:i:s a').' - '.$message.PHP_EOL;
fwrite($this->_file, $message);
}
}
?>
public function __construct($file, DateRetriever $date)
{
$this->date = $date;
$this->_file = fopen($file, 'a');
}
public function write($message)
{
$message = $this->date->getCurrentDate('m/d/Y h:i:s a').' - '.$message.PHP_EOL;
fwrite($this->_file, $message);
}
现在,这并不完全正确,但非常接近。这里的要点是:您的测试实际上测试了三件事:1)获取当前时间的方式2)日志的去向3)日志中包含的内容/它们的格式
我只是采用了获取当前时间的方式,理想情况下,您将采用将日志保存到文件系统的方式,可能是在FileSystemManager中。这样,您就可以分别测试“文件系统”功能、“getCurrentDate”功能和“日志内容”业务规则。现在,您有了一个可重用的文件系统类和一个可重用的日期类,这两个类在将来很可能都需要
我认为TDD最好的特性之一是,它迫使您将这样的概念分解为独立的单元,然后进行单元测试。Bob Martin有一些关于这类事情的非常有趣的想法和帖子,就是一个例子。如果您不想像Steve建议的那样为这么小的类注入日期时间源,您可以更改断言以检查时间格式而不是实际值
$regExp = '/^[0-9\/: ]+(am|pm) - This is a log message$/';
这样,就不需要调用str\u replace()
您还缺少验证现有文件是否将被追加而不是替换的测试。Hi-thom。欢迎来到StackOverflow。这个网站上的好问题包括一点代码(就像你的一样),并询问有关该代码的特定问题。对于“更好的方法”的代码审查和讨论,您可能会在上得到更好的答案。谢谢,有什么方法可以迁移我的问题吗?怎么用?谢谢。@thom:把它标上。在单元测试中使用常量来保持文件名是一种糟糕的做法。