PHPUnit setUp loves test methods

Quoting PHPUnit’ entry about fixtures

PHPUnit supports sharing the setup code. Before a test method is run, a template method called setUp() is invoked. setUp() is where you create the objects against which you will test. Once the test method has finished running, whether it succeeded or failed, another template method called tearDown() is invoked. tearDown() is where you clean up the objects against which you tested.

Which is clear and concise and I still did not get it.
My daily coding show (metaphorical here) was stopped by this code in my test file

protected $mainPath;
protected $controllersPath;
protected $controllerPath;
protected $viewsPath;
protected $viewPath;
protected $scriptsPath;
protected $scriptPath;
protected $minScriptPath;
protected $stylesPath;
protected $stylePath;
protected $minStylePath;

protected function setUp()
{
    // a valid path to a valid main file
    $this->mainPath = dirname(dirname(__FILE__)) . '/mvc_helpers/TestMain.php';
    $this->controllersPath = dirname(dirname(__FILE__)) . '/mvc_helpers/controllers';
    $this->controllerPath = dirname(dirname(__FILE__)) . '/mvc_helpers/controllers/FirstController.php';
    $this->viewsPath = dirname(dirname(__FILE__)) . '/mvc_helpers/views';
    $this->viewPath = dirname(dirname(__FILE__)) . '/mvc_helpers/views/FirstView.php';
    $this->scriptsPath = dirname(dirname(__FILE__)) . '/mvc_helpers/scripts';
    $this->scriptPath = dirname(dirname(__FILE__)) . '/mvc_helpers/scripts/FirstScript.js';
    $this->minScriptPath = dirname(dirname(__FILE__)) . '/mvc_helpers/scripts/FirstScript.min.js';
    $this->stylesPath = dirname(dirname(__FILE__)) . '/mvc_helpers/styles';
    $this->stylePath = dirname(dirname(__FILE__)) . '/mvc_helpers/styles/FirstStyle.css';
    $this->minStylePath = dirname(dirname(__FILE__)) . '/mvc_helpers/styles/FirstStyle.min.css';
}

    public function validFilePathsProvider()
{
    return array(
        array($this->mainPath) ,
        array($this->controllersPath) ,
        array($this->controllerPath) ,
        array($this->viewsPath) ,
        array($this->viewPath) ,
        array($this->scriptsPath) ,
        array($this->scriptPath) ,
        array($this->minScriptPath) ,
        array($this->stylesPath) ,
        array($this->stylePath) ,
        array($this->minStylePath)
        );
}

/**
 * @dataProvider validFilePathsProvider
 */
public function testWillResolveFromStartingPaths($startingPath)
{
    $sut = new FilePathResolver($startingPath); // <<<< I will throw errors
    $this->assertEquals($startingPath,$sut->path);
    $this->assertEquals($this->controllersPath, $sut->getControllersPath());
    $this->assertEquals($this->controllerPath, $sut->getControllerPath('First'));
    $this->assertEquals($this->viewsPath, $sut->getViewsPath());
    $this->assertEquals($this->viewPath, $sut->getViewPath('First'));
    $this->assertEquals($this->scriptsPath, $sut->getScriptsPath());
    $this->assertEquals($this->scriptPath, $sut->getScriptPath('First'));
    $this->assertEquals($this->minScriptPath, $sut->getScriptPath('First', $min = true));
    $this->assertEquals($this->stylesPath, $sut->getStylesPath());
    $this->assertEquals($this->stylePath, $sut->getStylePath('First'));
    $this->assertEquals($this->minStylePath, $sut->getStylePath('First', $min = true));
}

failing all the tests due to the fact that the FilePathsResolver class will only take strings as an input, namely absolute paths to a file, and, in the above highlighted line, $startingPath was not.
How is it? My data provider function, validFilePathsProvider provided null strings in place of the one I had set in the setUp method.

I got the invocation order wrong

I thought PHPunit would have called my functions in this order

  1. setUp
  2. validFilePathsProvider to provide file paths to…
  3. testWillResolveFromStartingPaths

where 2 and 3 will loop due to the data providing mechanism PHPUnit comes with.
I was wrong and the actual order is

  1. validFilePathsProvider
  2. setUp
  3. testWillResolveFromStartingPaths

And hence I can well see that my test method got fed with non initialized strings.

SetUp is made to initialize stuff for the test because it really loves just the tests

Hence I’ve moved the setting of the properties in separate function

protected function setValidFilePaths(){
    // a valid path to a valid main file
    $this->mainPath = dirname(dirname(__FILE__)) . '/mvc_helpers/TestMain.php';
    $this->controllersPath = dirname(dirname(__FILE__)) . '/mvc_helpers/controllers';
    $this->controllerPath = dirname(dirname(__FILE__)) . '/mvc_helpers/controllers/FirstController.php';
    $this->viewsPath = dirname(dirname(__FILE__)) . '/mvc_helpers/views';
    $this->viewPath = dirname(dirname(__FILE__)) . '/mvc_helpers/views/FirstView.php';
    $this->scriptsPath = dirname(dirname(__FILE__)) . '/mvc_helpers/scripts';
    $this->scriptPath = dirname(dirname(__FILE__)) . '/mvc_helpers/scripts/FirstScript.js';
    $this->minScriptPath = dirname(dirname(__FILE__)) . '/mvc_helpers/scripts/FirstScript.min.js';
    $this->stylesPath = dirname(dirname(__FILE__)) . '/mvc_helpers/styles';
    $this->stylePath = dirname(dirname(__FILE__)) . '/mvc_helpers/styles/FirstStyle.css';
    $this->minStylePath = dirname(dirname(__FILE__)) . '/mvc_helpers/styles/FirstStyle.min.css';
}

for code re-usability (but I could have moved the code into the data provider method)

public function validFilePathsProvider()
{
    $this->setValidFilePaths();
    return array(
        array($this->mainPath) ,
        array($this->controllersPath) ,
        array($this->controllerPath) ,
        array($this->viewsPath) ,
        array($this->viewPath) ,
        array($this->scriptsPath) ,
        array($this->scriptPath) ,
        array($this->minScriptPath) ,
        array($this->stylesPath) ,
        array($this->stylePath) ,
        array($this->minStylePath)
        );
}

while the rest of test code remains the same and will not generate errors anymore.
So today’s gotcha! about PHPUnit is that setUp is the last method to be invoked before the real test method is. And not the first one in the class.