I usually use dependency injection (DI), but want to get better with traits since they seem like they can fulfill a similar role while still using composition instead of inheritance. The issue I’m running into is I cannot figure out the best way to make sure that the code under test (CUT) is properly calling methods on said trait – this seems similar to the issues I’ve run into in the past with inheritance?
When doing DI, I create an interface and then a test double that implements the interface/contract with functions on it that allow you to check calls occurred. You can then check these in the test case during the assertion phase.
The issue is I’m a bit stuck with how to do this with traits without adding extra code to the actual implementation of the trait.
For example, let’s pretend we have a trait:
trait CanLog
{
protected function log($level, $message)
{
// implementation goes here
}
}
class ClassThatWillLog
{
use CanLog;
public function foobar()
{
// do some stuff
$this->log("INFO", "I finished successfully!");
}
}
I want to assert that `$this->log() was called with “INFO” and “I finished successfully!” in this case at the end of the test. I don’t care what the trait actually did with that because that’s the job of the test case testing the trait itself.
The two, probably naive ways, that come to mind are:
- Creating some form of call log that can be accessed later via a getter.
- Creating a callback in
CanLog::log()
The first feels a bit, gross?, in that I’m adding code that technically isn’t necessary and only exists for the purposes of testing and really shouldn’t be included in the production code. The second option feels a bit over-engineered if I don’t need that callback for some other purpose. I’m curious if I’m missing something really obvious here.