2

I test a config class, which is parsing a config file and allows me to get the various settings for an app.

My goal is to mock the parse() method of the Config class, which is called in the constructor and to set what this method is returning in the constructor.

This way, it prevents file_get_contents() from being called (in the parse() method) and enables me to have a Config class with the config property already set to contain an array of properties.

But I haven't succeeded doing that.

Here is the code:

The config class:

<?php namespace Example;

use Symfony\Component\Yaml\Parser;

class Config
{

private $parser;
private $config;

public function __construct(Parser $parser, $filePath)
{
    $this->parser = $parser;
    $this->config = $this->parse($filePath);
}

public function parse($filePath)
{
    $fileAsString = file_get_contents($filePath);

    if (false === $fileAsString) {
        throw new \Exception('Cannot get config file.');
    }

    return $this->parser->parse($fileAsString);
}

public function get($path = null)
{
    if ($path) {
        $config = $this->config;

        $path = explode('/', $path);

        foreach ($path as $bit) {
            if (isset($config[$bit])) {
                $config = $config[$bit];
            }
        }

        return $config;

    }

    return false;
    }

}

The test:

<?php namespace Example;

class ConfigTest extends \PHPUnit_Framework_TestCase
{

    private function getConfigTestMock($configAsArray)
    {
        $parser = $this->getMockBuilder('\Symfony\Component\Yaml\Parser')
            ->getMock();

        $configMock = $this->getMockBuilder('Example\Config')
            ->setConstructorArgs([$parser, $configAsArray])
            ->setMethods(['parse', 'get'])
            ->getMock();

        $configMock->expects($this->once())
            ->method('parse')
            ->willReturn($configAsArray);

        return $configMock;
    }

    /**
     * @test
     */
    public function get_returns_false_if_no_path_given()
    {
        $configMock = $this->getConfigTestMock(['param1' => 'value1']);

        // Testing further...

    }
}

2 Answers 2

1

I suggest you to make a functional test mocking the interaction with the file system, without do partial mocking of the tested class.

I recently discover the vfsStream library used in a great article of William Durand about Symfony2 and DDD.

So you can install this library in your composer.json (I tested the solution with the 1.4 version) and try this example test class:

<?php


namespace Acme\DemoBundle\Tests;


use Acme\DemoBundle\Example\Config;
use org\bovigo\vfs\vfsStream;
use Symfony\Component\Yaml\Parser;

class ConfigTest extends \PHPUnit_Framework_TestCase
{


    /**
     * @test
     */
    public function valid_content()
    {
        $content = "param1: value1";

        $root      = vfsStream::setup();

        $file = vfsStream::newFile('example.txt')
            ->withContent($content)
            ->at($root);

        $filepath = $file->url();
        $parser = new Parser();

        $config = new Config($parser, $filepath);
        $this->assertEquals("value1", $config->get("param1"));

    }

}

Hope this help

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for this great solution and the links! Wish I could give you more points for this answer! :)
1

For test the Config class you need to mock only the Parser and use the real Config class. As Example:

<?php


namespace Acme\DemoBundle\Tests;


use Acme\DemoBundle\Example\Config;

class ConfigTest extends \PHPUnit_Framework_TestCase
{

    private function getConfigTestMock($configAsArray)
    {
        $parser = $this->getMockBuilder('\Symfony\Component\Yaml\Parser')
            ->getMock();


        $parser->expects($this->once())
            ->method('parse')
            ->willReturn($configAsArray);

        $configMock = new Config($parser,"fakePath");

        return $configMock;
    }

    /**
     * @test
     */
    public function get_returns_false_if_no_path_given()
    {
        $configMock = $this->getConfigTestMock(['param1' => 'value1']);
        $this->assertEquals("value1",$configMock->get("param1"));

        // Testing further...

    }
}

Hope this help

2 Comments

I realized I made a mistake in my question which made it look like the problem was with the parse() method of the YAML Parser while actually my question is about how to mock the parse() method of the Config class and control what it returns in the constructor.
Hi @IamZesh i see your update, i will investigate and response to you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.