PHP Trait testing

I’d like to know how you test your traits and what’s your favourite way to do it. I have found two different approaches that I want to share with you. Please comment if you apply different techniques or have different opinions.

Imagine a Salesman entity that we want to change it’s name, the name is not allowed to be 255 longer. If so, we’ll throw an exception. We have decided to implemented with a trait (we’ll see why and what pattern is related to in another post), ValidationTrait. When want to unit test it, of course. Here is the trait:

<?php

namespace Domain\Model\Validation;

/**
 * Trait ValidationTrait
 * @package Domain\Model\Validation
 */
trait ValidationTrait
{
    /**
     * @param  string                 $value
     * @param  int                    $maxLength
     * @throws StringTooLongException
     */
    private function checkMaxLength($value, $maxLength)
    {
        if (strlen($value) > $maxLength) {
            throw new StringTooLongException();
        }
    }
}

The two different approaches are:

  1. Direct “use” in TestCase
  2. Dummy class “using” Trait

Direct “use” in TestCase

The first approach is using the Trait in the TestCase:

<?php
namespace Domain\Model\Validation;

use Domain\Model\Validation\StringTooLongException;

class ValidationTraitTest extends \PHPUnit_Framework_TestCase
{
    use ValidationTrait;

    /**
     * @test
     * @dataProvider validStringsLengthLimitsDataProvider
     */
    public function validStringsLengthLimits($string, $maxlength)
    {
        $result = $this->checkMaxLength($string, $maxlength);
        $this->assertNull($result);
    }

    public function validStringsLengthLimitsDataProvider()
    {
        return [
            [null, 0],
            ['', 0],
            ['#', 1],
            ['#', 2],
        ];
    }

    /**
     * @test
     * @dataProvider invalidStringsLengthLimitsDataProvider
     * @expectedException StringTooLongException
     */
    public function invalidStringsLengthLimits($string, $maxlength)
    {
        $this->checkMaxLength($string, $maxlength);
    }

    public function invalidStringsLengthLimitsDataProvider()
    {
        return [
            [null, -1],
            ['', -1],
            ['#', 0],
            ['##', 1],
        ];
    }
}

Easy, elegant and no more elements needed. The only problem I see here, it’s a matter of naming collision with the methods in the tests and the Trait that could be resolved with the trait aliasing capabilities.

Dummy class “using” Trait

The second approach means creating a dummy class that will use the trait and then unit test the dummy class. Let’s check a possible solution:

<?php
namespace Domain\Model\Validation;

use Domain\Model\Validation\StringTooLongException;

/**
 * Class ValidationTraitDummyClass
 * @package Domain\Model\Validation
 */
class ValidationTraitDummyClass
{
    use ValidationTrait;
}

class ValidationTraitTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @var ValidationTraitDummyClass
     */
    private $dummy;

    protected function setUp()
    {
        $this->dummy = new ValidationTraitDummyClass();
    }

    /**
     * @test
     * @dataProvider validStringsLengthLimitsDataProvider
     */
    public function testValidStringsLengthLimits($string, $maxlength)
    {
        $result = $this->dummy->checkMaxLength($string, $maxlength);
        $this->assertNull($result);
    }

    public function validStringsLengthLimitsDataProvider()
    {
        return [
            [null, 0],
            ['', 0],
            ['#', 1],
            ['#', 2],
        ];
    }

    /**
     * @test
     * @dataProvider invalidStringsLengthLimitsDataProvider
     * @expectedException StringTooLongException
     */
    public function testInvalidStringsLengthLimits($string, $maxlength)
    {
        $this->dummy->checkMaxLength($string, $maxlength);
    }

    public function invalidStringsLengthLimitsDataProvider()
    {
        return [
            [null, -1],
            ['', -1],
            ['#', 0],
            ['##', 1],
        ];
    }
}

What’s the problem here? Our trait has a private method, so we have to tune a bit our example. Remark that with a public method, our example would be ready. So, let’s try to update our dummy class to make the work:

/**
 * Class ValidationTraitDummyClass
 * @package Domain\Model\Validation
 */
class ValidationTraitDummyClass
{
    use ValidationTrait;

    public function checkMaxLength($string, $maxlength)
    {
        $this->checkMaxLength($string, $maxlength);
    }
}

Ok, that do the trick, but it’s not as elegant as the first approache, isn’t it?

Conclusion

Based on the different details and cases, in my opinion, the first approach, Direct “use” in the test case is better than the other one. It has no drawbacks and it’s more elegant for me. Thoughts?