PHPUnit - Mocking a trait

11.4k Views Asked by At

I have a trait that is used by multiple classes, i.e

class SomeClass
{
     use TimeoutTrait;

     function handle() {
         $this->traitFunction()    // can this be mocked?
     }
}

PHP unit is capable to mock the traitFunction()?.

Thanks in advance for the help.

Greetings

3

There are 3 best solutions below

1
On BEST ANSWER

Traits are code containers which code is "copy-pasted" by compiler into a class you want to use it in, thus making it reusable all over the world.

Generally, there is nothing special to do with trait functions in unit tests, because when class is instantiated trait functions don't make any difference from functions that could be copy-pasted right they are written in trait inside your class.

So, don't hesitate to mock your trait function the same way as any other regular function defined inside the class.

0
On

The simplest way is to mock the parent class and then do your unit tests on the trait. Or you can make a specific class to implement the trait, solely for unit testing, but that assumes your trait doesn't do anything that interacts with the parent or vice versa.

1
On

When you mock a class with PHPUnit it extends the class and overrides the methods that you are mocking with a replacement. So in your case, it would look like this:

$sut = $this->getMockBuilder('SomeClass')
    ->setMethods(['traitFunction'])
    ->getMock();

$sut->expects($this->once())
    ->method('traitFunction');

$sut->handle();

Though doing this is not a good idea, IMO. You are specifying how your class should do something rather than what it is supposed to do. If the method that your trait is providing is complicated enough to warrant its own class that you feel that you need to mock it. Make it a stand-alone class and use the strategy pattern to pass in the behavior.

Your class would like this:

Class SomeClass {
    private $handler;

    public function __construct(ClassFormerlyATrait $handler) {
        $this->handler = $handler;
    }

    public function handler() {
        $this->handler->traitFunction();
    }
}

Class ClassFormerlyATrait {
    public function traitFunction() {
     // Does whatever the trait did.
    }
}

This makes your design a little more complicated but you are now able to adapt your class to changes. For example, you need traitFunction to do something slightly different under certain circumstances. You would extend the ClassFormerlyATrait with the new functionality and pass it in to SomeClass instead without worrying about breaking any existing functionality.