Yii 1.1: Access log output from unit tests

2 followers

What is this good for?

Say, you want to write a test for a component which provides a caching feature. How would you know, that some method of your component returns a cached result? With the solution described here you can inspect all log outputs. So you could search the logs for accesses to the DB to really make sure, that the result was served from cache.

What you need

First create a simple log router class. All it does is to keep the log messages in memory and makes them available in a static variable. You could put this class into the components/ folder of your application:

<?php
class DebugLogRoute extends CLogRoute
{
    /**
     * @var array list of messages in this format:
     * array(
     *   [0] => message (string)
     *   [1] => level (string)
     *   [2] => category (string)
     *   [3] => timestamp (float, obtained by microtime(true)
     *  )
     */
    public static $messages=array();
 
    protected function processLogs($logs)
    {
        foreach($logs as $log)
            self::$messages[]=$log;
    }
 
    /**
     * Reset collected messages
     */
    public static function flushMessages()
    {
        self::$messages=array();
    }
 
    /**
     * @param string $pattern regex pattern to search for
     * @param mixed $l optional level to search for
     * @param mixed $c optional category to search for
     * @return bool wether message with given pattern, level and category was found
     */
    public static function hasMessage($pattern, $l=null, $c=null)
    {
        foreach(self::$messages as $m)
            if(
                preg_match($pattern, $m[0]) && 
                ($l===null || $m[1]===$l) && 
                ($c===null || $m[2]===$c)
            )
                return true;
 
        return false;
    }
}

Add the above class to your test configuration in config/test.php:

<?php
'components'=>array(
    'log'=>array(
        'class'=>'CLogRouter',
        'routes'=>array(
            array('class'=>'DebugLogRoute')
        ),
    ),
    ...

How to use from a unit test

Now inside a unit test you can access the log messages like this:

<?php
public function testSomething()
{
    $logger = Yii::getLogger();
 
    // Flush all messages so far and reset debug log route
    $logger->flush(true);
    DebugLogRoute::flushMessages();
 
    // ... do tests and add log messages here ...
 
    $logger->flush(true);
    $logs=DebugLogRoute::$messages;
 
    // Inspect logs, for example:
    $this->assertTrue(
        DebugLogRoute::hasMessage('Serving .* from cache', 
        'trace',
        'system.caching.CApcCache'
    );
 
    DebugLogRoute::flushMessages();
 
    // ... more tests ...
 
    $logger->flush(true);
    $logs=DebugLogRoute::$messages;
 
    // ... inspect $logs ...
}

Total 2 comments

#8643 report it
Mike at 2012/06/15 04:19am
Re: would be nice ...

There you go :)

#8625 report it
redguy at 2012/06/14 11:43am
would be nice...

...to have methods that allow to search in those logs, like:

hasLogWithString( 'xxx' ); hasLogInCategory( 'application.xxx' ); hasWarnings(); hasErrors(); etc...

those would be handful when dealing with unittests :)

Leave a comment

Please to leave your comment.

Write new article
  • Written by: Mike
  • Category: Tips
  • Yii Version: 1.1
  • Votes: +4
  • Viewed: 5,345 times
  • Created on: Jun 14, 2012
  • Last updated: Jun 15, 2012
  • Tags: testing, Logging, debug