V
V
vism2015-05-22 15:29:42
Yii
vism, 2015-05-22 15:29:42

How to mock a static method in tests in yii2?

The method under test calls a static method of another class (FileHelper::createDirectory($path);).
How to mock this method in yii2?

protected function _generateFolders()
    {
        $folders = str_split($this->hash, self::FOLDER_TITLE_LENGTH);
        $folders = array_slice($folders, 0, $this->foldersDepth);
        $folders = implode('/', $folders) .
            ($this->accessDir ? '/' . $this->accessDir : '');

        $path = self::getPathToFiles() . '/' . $folders;
        FileHelper::createDirectory($path);

        return $folders;
    }

Just static methods can be replaced using https://github.com/Codeception/AspectMock
But in yii it is somehow buggy ..

Answer the question

In order to leave comments, you need to log in

3 answer(s)
H
He11ion, 2015-05-22
@He11ion

In phpunit, no way.

D
D', 2015-05-22
@Denormalization

I looked at the Yii code, it turns out they really use static methods for helpers ...
I don’t write in Yii, but I can advise you to stop using their static classes directly, and work through your own wrapper.
That is, make the MySuperHelpers class, in which to encapsulate all the work with statics, and already use your class everywhere. Those:

<?php

class MyHelpers {

  public function makeDirectory($path)
  {
    return FileHelper::createDirectory($path);
  }

}

And you can easily mock your class where you need it.

M
matperez, 2015-05-27
@matperez

By the way, another option. If you have a method in your class that uses statics or, say, should access the file system, which you don’t want to do in tests, you can explicitly move this functionality into a separate private method and lock it up. Get something like

class Actor
{
    public function generateFolders()
    {
        $folders = str_split($this->hash, self::FOLDER_TITLE_LENGTH);
        $folders = array_slice($folders, 0, $this->foldersDepth);
        $folders = implode('/', $folders) .
            ($this->accessDir ? '/' . $this->accessDir : '');

        $path = self::getPathToFiles() . '/' . $folders;
        $this->createDirectory($path);
        return $folders;
    }
    
    protected function createDirectory($path)
    {
        return  FileHelper::createDirectory($path);
    }
}

In this code, it is already quite easy to hack an explicit call to a static method. The rest of the methods will work as usual.
$actor = $this->getMock('Actor', ['createDirectory']);
        $actor->expects($this->any())->method('createDirectory')->willReturn(true);

This is easier than implementing a full-fledged DI with the substitution of the implementation of interfaces.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question