How to mock ActiveRecord

If you want to mock AR that doesn’t try to connect to database you can do it in the following way (if using PHPUnit):

$post = $this->getMockBuilder('\app\model\Post')
    ->setMethods(['save', 'attributes'])


The catch is that we need to override attributes() method since ActiveRecord by default is getting attributes list from database schema which we’re trying to avoid.


Based on this solution, here is the way to stub AR relations:

$attributes = (new Post)->attributes();
$relations = ['comments', 'author'];

/** @var Post|MockObject $task */
$post = $this->getMockBuilder(Post::class)

// Stub relations by turn them as an usual model attributes.
    ->willReturn(array_merge($attributes, $relations));

// Now we can assign values to relations that in normal 
// circumstances impossible due to "read only" access to them.

$post->comments = [new Comment];
$post->author = new Author;

// Assign an ordinary attribute, for an example

$post->title = 'the title of the post';

Instead of hard coded class name, which one is considered a better practice:
$post = $this->getMockBuilder(Post::className())
or even:
$post = $this->getMockBuilder(Post::class)

1 Like

Note: This kind of destroys the normal workflow, since validate() is no longer run. The code has to manually run validate() before running save(), which is a bit awkward. Maybe there’s a better way to mock this particular method? Example:

                function() use ($post) {
                    return $post->validate();

(Running Yii 1.1.)

Is there any easier way, if I need just mock DB side, without mocking AR flow (triggers/events, behaviors, validations)?

Replace the entire model with a dummy? It might help if you show some code.

Or mock the getDatabase() static function, if possible…

Did you find a solution to this? I think I’m in the same situation.

Gonna give Mocker a go and see if I can mock the static method getDb.

Or maybe it’s enough to mock out the attributes method to avoid the db call. :slight_smile:

What did you end up with?
Was reading and couldn’t find your conclusion!