jeudi 23 janvier 2020

Using @dataProvider in abstract base class with implementation in actual test

I am trying to create a base class for testing validation rules from Laravel, although what is being tested is not really the issue in this case.

Here is what I made:

<?php

namespace Tests\Unit\Rules;

use Tests\TestCase;
use Illuminate\Contracts\Validation\Rule;

abstract class RuleTestCase extends TestCase
{
    protected Rule $rule;

    public function setUp(): void
    {
        parent::setUp();

        $this->rule = $this->initializeRule();
    }

    /**
     * @dataProvider validRuleInput
     *
     * @param mixed $value
     */
    public function testRuleWithValidInput($value): void
    {
        $this->assertTrue($this->rule->passes('attribute', $value));
    }

    /**
     * @dataProvider invalidRuleInput
     *
     * @param mixed $value
     */
    public function testRuleWithInvalidInput($value): void
    {
        $this->assertFalse($this->rule->passes('attribute', $value));
    }

    abstract public function validRuleInput(): array;

    abstract public function invalidRuleInput(): array;

    abstract public function initializeRule(): Rule;
}

And this is how I would like to implement it:

<?php

namespace Tests\Unit\Rules\Text;

use App\Rules\Text\ContainsLetters;
use Illuminate\Contracts\Validation\Rule;
use Tests\Unit\Rules\RuleTestCase;

class ContainsLettersTest extends RuleTestCase
{
    public function validRuleInput(): array
    {
        return [
            'abcd',
            'a2c4',
            '!b#d',
        ];
    }

    public function invalidRuleInput(): array
    {
        return [
            '1234',
            '!@#$',
            '1@3$',
        ];
    }

    public function initializeRule(): Rule
    {
        return new ContainsLetters;
    }
}

I would expect this to work since the data providers are implemented in the class that is being tested although the actual test method is implemented in the abstract base class.

When executing phpunit I get the following warning:

1) Warning
The data provider specified for Tests\Unit\Rules\Text\ContainsLettersTest::testRuleWithValidInput is invalid.
Data set #0 is invalid.

This tells me that the test method on the abstract base class can be executed but it cannot resolve the implementation of the data providers.

I am not sure how to solve this and/or if it can be solved. I tried:

  • Googling, this brought up this which seems somewhat related but it looks like that was fixed/resolved a long time ago
  • Trying to add @dataProvider static::validRuleInput (after changing validRuleInput to be a public abstract static method

I would like my test cases to have as little boilerplate as possible and this seems like a great way to achieve that since all the rule classes do is validating some input and don't need any advance tests and I would like to not have each test have all the test boilerplate validating that but focus on the rule being tested and the data that is supposed to be (in)valid. If there is a better way to do this I'm ofcourse all ears to.

Versions: PHPUnit 8.5.2 & PHP 7.4.0

Aucun commentaire:

Enregistrer un commentaire