psalm-plugin-phpunit icon indicating copy to clipboard operation
psalm-plugin-phpunit copied to clipboard

Erroneous TooFewArguments on combination of data provider and dependent test

Open remorhaz opened this issue 4 years ago • 6 comments

In my case, test case class has the following structure:

<?php

class MyTest extends \PHPUnit\Framework\TestCase
{

    public function testOne(): string
    {
        // ...
        return 'bar';
    }

    /**
     * @dataProvider providerFoo
     * @depends testOne
     */
    public function testSecond(string $foo, string $bar): void
    {
        // ...
    }

    /**
     * @return iterable<string, array{string}>
    public function providerFoo(): iterable
    {
        return [['foo']];
    }
}

In this case, testSecond() method gets $foo = 'foo' and $bar = 'bar' arguments; but Psalm reports TooFewArguments (probably ignoring dependency if data provider is set).

P.S.: Anyone please tell me how to suppress this bug until it gets fixed. Adding @psalm-suppress TooFewArguments both in provider or test method docblocks doesn't help.

remorhaz avatar Jul 10 '21 07:07 remorhaz

Currently the plugin has no idea what @depends mean.

Anyone please tell me how to suppress this bug until it gets fixed. Adding @psalm-suppress TooFewArguments both in provider or test method docblocks doesn't help.

You may try to suppress it via config file. Didn't test it myself, but I think it might work:

        <TooFewArguments>
            <errorLevel type="suppress">
                <referencedFunction name="Tests\TestCase::testThatFails" />
            </errorLevel>
        </TooFewArguments>

weirdan avatar Jul 10 '21 09:07 weirdan

Dev notes:

When a test receives input from both a @dataProvider method and from one or more tests it @depends on, the arguments from the data provider will come before the ones from depended-upon tests

The following is not really clear:

The result of a test that uses data providers cannot be injected into a depending test.

weirdan avatar Jul 10 '21 09:07 weirdan

You may try to suppress it via config file. Didn't test it myself, but I think it might work

Yep, the following does work:

Feature: Suppression
  In order to avoid false positives
  As a Psalm user
  I need to be able to suppress issues emitted by the plugin

  Scenario: Can suppress TooFewArguments via config
    Given I have the following config
      """
      <?xml version="1.0"?>
      <psalm totallyTyped="true" %s>
        <projectFiles>
          <directory name="."/>
          <ignoreFiles> <directory name="../../vendor"/> </ignoreFiles>
        </projectFiles>
        <plugins>
          <pluginClass class="Psalm\PhpUnitPlugin\Plugin"/>
        </plugins>
        <issueHandlers>
          <TooFewArguments>
            <errorLevel type="suppress">
              <referencedFunction name="NS\MyTestCase::testConsumer" />
            </errorLevel>
          </TooFewArguments>
        </issueHandlers>
      </psalm>
      """
    And I have the following code
      """
      <?php
      namespace NS;
      use PHPUnit\Framework\TestCase;

      class MyTestCase extends TestCase
      {
        public function testProducer(): int
        {
          return 42;
        }

        /**
         * @depends testProducer
         * @dataProvider provide
         */
        public function testConsumer(int $provided, int $dependedUpon): void {}

        /** @return iterable<int,array{int}> */
        public function provide() {
          yield [1];
        }
      }
      """
    When I run Psalm
    Then I see no errors

weirdan avatar Jul 10 '21 09:07 weirdan

The result of a test that uses data providers cannot be injected into a depending test.

This means that if you make testSecond() dependent of testOne() (like in my example), then testOne() cannot use data provider (but testSecond() can, as it does in my example).

remorhaz avatar Jul 10 '21 16:07 remorhaz

I'm curious what would happen if it does?

weirdan avatar Jul 10 '21 23:07 weirdan

I'm curious what would happen if it does?

Just as written - it doesn't inject any data from data-provided test, I'm just getting null in "dependent" argument (or TypeError if it's type-hinted).

remorhaz avatar Jul 12 '21 06:07 remorhaz