rawr/cross-data-providers

This package is abandoned and no longer maintained. The author suggests using the rawr/phpunit-data-provider package instead.

Lightweight builder for PhpUnit data providers

3.0.0 2023-08-06 11:40 UTC

This package is auto-updated.

Last update: 2023-08-07 18:48:13 UTC


README

t.regx.png

Helper for PhpUnit @dataProvider

Handy require-dev testing tool for PhpUnit. It allows to manage data providers with zip(), join(), cross(), pairs(), slice() and more.

Build Status Coverage Status Dependencies Repository Size License Composer lock

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

PRs Welcome

  1. Installation
  2. Overview
  3. Documentation
  4. Documentation
  5. Migration

Installation

Installation for PHP 7.1 and later:

composer require --dev rawr/phpunit-data-provider

Overview

DataProvider can be used to build, compose and edit data providers to be used with PhpUnit by @sebastianbergmann.

DataProvider::list()

DataProvider::list() provides a list of elements. Test is invoked each time with a single argument.

/**
 * @test 
 * @dataProvider colors
 */
public function test(string $color): void {
  // your test here
}

public function colors(): DataProvider {
  return DataProvider::list("blue", "yellow", "red");
}

list.png

Additionally, DataProvider::list() names rows based on values.

DataProvider::join()

Vertically join data providers together.

💡 Useful when two data providers are used in other tests, and a new test should use both of them.

/**
 * @test 
 * @dataProvider colors
 */
public function test(string $color, string $thing): void {
  // your test here
}

public function colors(): DataProvider {
  return DataProvider::join($this->natureColors(), $this->shadeColors());
}

public function natureColors(): DataProvider {
  return DataProvider::sets(
    ["blue", "sky"], 
    ["yellow", "sun"],
    ["red", "apple"]
  );
}

public function shadeColors(): array {
  return [
    'hair' => ["gray", "hair"], 
    'ink' => ["black", "ink"],
    'dust' => ["lightgray", "dust"]
  ];
}

join.png

DataProvider::zip()

Horizontally join data providers together.

💡 Useful for keeping data providers clean and simple.

/**
 * @test 
 * @dataProvider colors
 */
public function test($blueColor, $blueThing, $yellowThing, $redThing): void {
  // your test here
}

public function colors(): DataProvider {
  return DataProvider::zip($this->blueThings(), $this->yellowThings(), $this->redThings());
}

public function blueThings(): DataProvider {
  return DataProvider::sets(
    ["blue", "pen"],
    ["light blue", "shirt"],
    ["deep blue", "ocean"]
  );
}

public function yellowThings(): iterable {
  return DataProvider::list("sun", "apple", "lemon");
}

public function redThings(): iterable {
  yield ["apple"];
  yield ["cranberry"];
  yield ["car"];
}

zip.png

DataProvider::cross()

Creates a square matrix of given data providers.

💡 Useful for testing all combinations of arguments.

/**
 * @test 
 * @dataProvider shadedColors
 */
public function test(string $shade, string $color): void {
  // your test here
}

public function shadedColors(): DataProvider {
  return DataProvider::cross($this->shades(), $this->colors());
}

public function shades(): iterable {
  return DataProvider::list("light", "standard", "dark");
}

public function colors(): array {
  return [
    ["blue"], ["yellow"], ["red"]
  ];
}

cross.png

DataProvider::pairs()

Calls test with two arguments. Each argument is paired with all of the other arguments.

Example shows a test paring image formats:

/**
 * @test
 * @dataProvider formats
 */
public function shouldConvertFile(string $from, string $to): void {
  // your test here
}

public function formats(): array {
  return DataProviders::distinctPairs('png', 'jpg', 'bmp');
}

pairs.png

DataProvider::of()

Instantiates a DataProvider from a raw-array accepted by PhpUnit.

public function example(): DataProvider {
  return DataProvider::of($this->rawArray());
}

public function rawArrayDataProvider(): array {
  return [
    'key' => ['argument 1', 'argument 2']
  ];
}

DataProvider::sets()

Provide multiple arguments for each a test. DataProvider::sets() names each row based on the values.

/**
 * @test 
 * @dataProvider colors
 */
public function test(string color, string $thing): void {
  // your test here
}

public function colors(): DataProvider {
  return DataProvider::sets(
    ["blue", "sky"], 
    ["yellow", "sun"],
    ["red", "apple"]
  );
}

sets.png

DataProvider::dictionary()

Specify a single argument for test. DataProvider::dictionary() names each row based on the provided array key.

/**
 * @test 
 * @dataProvider colors
 */
public function test(string color): void {
  // your test here
}

public function colors(): DataProvider {
  return DataProvider::dictionary([
    "custom key 1" => "blue", 
    "custom key 2" => "yellow", 
    "custom key 3" => "red"  
  ]);
}

dictionary.png

In most cases, DataProvider::list() should probably be used over DataProvider::dictionary(). Method ::dictionary() is useful when the arguments are not self-explanatory, for example:

public function ports(): DataProvider {
  return DataProvider::dictionary([
    "http"  => 80, 
    "https" => 443, 
    "ftp"   => 21  
  ]);
}

Documentation

Features

  • DataProvider accepts many provider types.
  • each builder method sets proper names for rows, based on values
  • properly handled duplicates in keys, formatting them in an informative manner
  • lazily evaluates iterators, calling them only once (even if the provider is used multiple times)

Functionalities

Creating new data providers:

  • DataProvider::list(), DataProvider::sets(), DataProvider::dictionary(), DataProvider::pairs(), DataProvider::distinctPairs()

Composing existing providers:

  • DataProvider::zip(), DataProvider::join(), DataProvider::cross(), DataProvider::of()

Editing existing providers:

  • DataProvider.slice(), DataProvider.drop()

Names

DataProvider sets proper names for each row based on values.

/**
 * @test 
 * @dataProvider colors
 */
public function test(string color, string $thing): void {
  // your test here
}

public function colors(): DataProvider {
  return DataProvider::sets(
    ["blue", "sky"], 
    ["yellow", "sun"],
    ["red", "apple"]
  );
}

names names

Documentation

Example usage

DataProvider::cross() returns an instance of DataProvider which is a square matrix of input data providers.

/**
 * @test
 * @dataProvider services
 */
public function shouldLogin(string $service, string $method, int $port): void {
  // your test here
}

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

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

public function services(): array {
  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],
  ];
}

DataProvider::cross() accepts data providers of different types: array, \Iterator, \IteratorAggregate, \Traversable, \Generator, iterable and DataProvider.

That means DataProvider can be composed together.

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

Advanced usage

DataProvider can be combined with other DataProviders as well as regular PhpUnit data providers.

/**
 * @test
 * @dataProvider urls
 */
public function test0(string $url): void {
  // your test here
}

/**
 * @test
 * @dataProvider services
 */
public function test1(string $url, string $name, string $method, int $port): void {
  // your test here
}

/**
 * @test
 * @dataProvider allServices
 */
public function test2(string $url, string $name, string $method, int $port): void {
  // your test here
}

public function urls(): DataProvider {
  return DataProvider::list('github.com', 'bitbucket.com', 'gitlab.com', 'sourceforge.net');
}

public function rawArrayProvider(): array {
  return [
    ['GitHub'],
    ['BitBucket'],
    ['GitLab'],
    ['SourceForge']
  ];
}

public function services(): DataProvider {
  return DataProvider::cross(
    DataProvider::zip($this->urls(), $this->rawArrayProvider()),
    DataProvider::sets(
      ['http', 80],
      ['https', 443],
      ['ssh', 22]));
}

public function allServices(): DataProvider {
  return DataProvider::join(
    $this->services(),
    $this->localServices()
  );
}

public function localServices(): array {
   return [
     'my local service' => ['localhost', 'local', 'http', '80']
   ];
}

Accepted types

DataProvider accepts any type of data provider:

Notes

Notes on DataProvider::join():

  • DataProvider::join() preserves names of each data provider, and also joins the names vertically. Duplicates in titles are preserved and presented appropriately.
  • DataProvider::join() accepts any type of data-provider.
  • DataProvider::join() is conceptually similar to calling \array_merge() on raw-array providers, but \array_merge() would override duplicate keys, while DataProvider::join() preserves duplicate keys, and titles them appropriately.
  • DataProvider::join() variadic arguments ...iterable and can be used to join many data providers
  • DataProvider::join() can only join data providers with the same amount of arguments in each row, otherwise IrregularDataProviderException is thrown.
  • DataProvider::join() accepts DataProvider or other iterable accepted by PhpUnit. If improper data-provider is passed, MalformedDataProviderException is thrown.

Notes on DataProvider::zip():

  • DataProvider::zip() preserves names of each data provider, and also joins them horizontally.
  • DataProvider::zip() accepts any type of data-provider.
  • DataProvider::zip() variadic arguments ...iterable and can zip many data providers
  • DataProvider::zip() can only zip data providers with the same amount of rows, otherwise IrregularDataProviderException is thrown. Additionally, each particular data provider must have the same amount of arguments in each row.
  • DataProvider::zip() accepts DataProvider or other iterable accepted by PhpUnit. If improper data-provider is passed, MalformedDataProviderException is thrown.

Note on DataProvider::pairs():

  • DataProvider::pairs() produces duplicate pairs (for example 'png', 'png'), while DataProvider::distinctPairs() only makes pairs of different arguments.

Note on DataProvider::sets():

  • DataProvider::sets() is similar to DataProvider::of(), but ::of() accepts an explicit name, while DataProvider::sets() titles the rows according to the values in the sets.

Migration from previous version

To use version 3.0.0, migrating from 2.4.0 or earlier:

  • Library namespace changed from \TRegx\DataProvider\ to \TRegx\PhpUnit\DataProviders\ .
  • Change \TRegx\DataProvider\DataProviders::cross() to \TRegx\PhpUnit\DataProviders\DataProvider::cross().
  • Change \TRegx\DataProvider\CrossDataProviders::cross() to \TRegx\PhpUnit\DataProviders\DataProvider::cross().
  • Change your data providers return type from array to iterable or \TRegx\PhpUnit\DataProviders\DataProvider.
  • Removed \TRegx\DataProvider\CrossDataProviders::builder(), use \TRegx\PhpUnit\DataProviders\DataProvider::cross() instead.