rawr/cross-data-providers

Allows you to use mix multiple PhpUnit @dataProvider without duplication

2.0.0 2019-10-19 21:08 UTC

README

t.regx.png

Cross @dataProviders

Handy require-dev testing tool for PhpUnit.

It allows you to create square matrices of your data providers!

Build Status Coverage Status Dependencies Repository Size License Composer lock

PHP Version PHP Version PHP Version PHP Version PHP Version PHP Version

PRs Welcome

  1. Installation
  2. Examples
  3. Supported PHP versions

Installation

Installation for PHP 5.6 and later:

$ composer require --dev rawr/cross-data-providers

Examples

Ever wanted to use multiple PhpUnit @dataProvider's with each other? Well, look no more :)

Imagine you have a service that allows you to log in to GitHub, BitBucket, SourceForge and GitLab with either SSH, HTTP or HTTPS and you want to test each possible configuration of those.

/**
 * @test
 * @dataProvider services
 */
public function shouldLogin(string $service, string $method, int $port) {
    // given
    $login = new Login($method, $port);
    
    // when
    $result = $login->log($service);
    
    // then
    $this->assertTrue($result);
}

function services() {
    return DataProviders::cross(
      [
        ['github.com'],
        ['bitbucket.com'],
        ['gitlab.com'],
        ['sourceforge.net']
      ],
      [
        ['http', 80],
        ['https', 443],
        ['ssh', 22]
      ]
    );
}

This is equivalent of having a regular dataProvider that is composed of 12 entries, that look like this:

function services() {
    return [
        ['github.com', 'http', 80],
        ['github.com', 'https', 443],
        ['github.com', 'ssh', 22],
        ['bitbucket.com', 'http', 80],
        ['bitbucket.com', 'https', 443],
        ['bitbucket.com', 'ssh', 22],
        ['gitlab.com', 'http', 80],
        ['gitlab.com', 'https', 443],
        ['gitlab.com', 'ssh', 22],
        ['sourceforge.net', 'http', 80],
        ['sourceforge.net', 'https', 443],
        ['sourceforge.net', 'ssh', 22],
    ];
}

More advanced example

Let's say that apart from the domain and the protocol, you'd also like to add the protocol port, and the service title. Further more, you'd like to have three strategies of connection: lazy, eager and a test dry run.

/**
 * @test
 * @dataProvider services
 */
public function shouldLogin(string $service, string $title, string $method, int $port, $strategy) {
    // given
    $login = new Login($method, $port);
    $login->useStrategy($strategy);
    
    // when
    $result = $login->log($service);
    
    // then
    $this->assertTrue($result, "Failed to login to $title");
}

function services() {
    return DataProviders::cross(
      [
        // First section (two paramters): $service and $title
        ['github.com',        'GitHub'],
        ['bitbucket.com',     'BitBucket'],
        ['gitlab.com',        'GitLab'],
        ['sourceforge.net',   'SourceForge'],
        ['www.gitkraken.com', 'Git Kraken']
      ],
      [
        // Second section: (pair of parameters): $method and $port
        ['http',  80],
        ['https', 443],
        ['ssh',   22]
      ],
      [
        // Last section: single parameter of $strategy
        new EagerStrategy(),
        new LazyStrategy(),
        new DryRunStrategy(),
      ]
    );
}

This is equal to a @dataProvider with 45 entries. The test will be run 45 times, each time with a unique combination of your sections :)

DataProvider builder

The above example with DataProviders::cross(), can also be written with a help of a builder:

function services() {
    return DataProviders::builder()
        ->addJoiningSection(
            ['github.com',        'GitHub'],
            ['bitbucket.com',     'BitBucket'],
            ['gitlab.com',        'GitLab'],
            ['sourceforge.net',   'SourceForge'],
            ['www.gitkraken.com', 'Git Kraken'])
        ->addJoiningSection(
            ['http',  80],
            ['https', 443],
            ['ssh',   22])
        ->addSection(
            new EagerStrategy(),
            new LazyStrategy(),
            new DryRunStrategy())
        ->build();
    );
}
  • addSection() simply adds another iteration of parameters. This is usually the default behaviour, since joined sections appear quite rarely in most applications.
  • addJoiningSection() allows for specifying multiple arguments for your PhpUnit method, that are supposed to be present together, like address and title or a protocol and port.

The most common use case could look similar to this:

/**
 * @test
 * @dataProvider trimMethods
 */
public function shouldTrimWhitespace(string $stretegy, string $whitespace) {
    // given
    $remover = new WhitespaceRemover($stretegy);

    // when
    $result = $remover->remove($whitespace);

    // then
    $this->assertEmpty($result);
}

function trimMethods() {
    return DataProviders::builder()
        ->addSection('trim', 'preg_replace', 'str_replace', 'mb_str_replace')
        ->addSection(' ', '\t', '\n', '\r', PHP_EOL)
        ->build();
    );
}