Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP和测试驱动开发-日志类测试_Php_Tdd_Phpunit_Logging - Fatal编程技术网

PHP和测试驱动开发-日志类测试

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

我现在开始使用TDD。我做了一些测试来编写一个日志类

我怎么知道我是否在测试中涵盖了所有内容

我错过任何测试了吗?测试“testShouldWriteANewLogEntry”使用日期和时间,我测试对了吗

你对我的考试有什么建议吗

日志测试
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:把它标上。在单元测试中使用常量来保持文件名是一种糟糕的做法。