Building PHPUnit data providers

Tired of having to write the same PHPUnit data provider methods over and over I’ve tried to keep testing code DRY. And probably over-engineered it.

The problem

Sticking to a philosophy of mine that hooks are developer options I’ve used truthy and falsy returning filters a lot throughout Route Pages code and need to test those filters in different contexts.
Long story made short: I’ve written methods like this too many times

public static function falsyValues() { return array( array( '' ), array( 0 ), array( null ), array( array() ), array( 0.0 ), array( '0' ), array( false ) ); } 

to be used in tests like

/** * @test * it should not create any page if the filter returns falsy values * @dataProvider falsyValues */ public function it_should_not_create_any_page_if_the_filter_returns_falsy_values( $falsyValue ) { add_filter( RoutePages::SHOULD_GENERATE_ROUTE_POSTS, function () use ( $falsyValue ) { return $falsyValue; } ); add_option( WPRouting_PersistableRoute::OPTION_ID, array( 'routeOne' => array( 'title' => 'Route one', 'permalink' => '^route-one$', 'generate' => 'page' ) ) ); $originalCount = get_posts( array( 'post_type' => 'page' ) ); $sut = new RoutePages_PageManager(); $sut->maybeGenerateRoutePages(); $newCount = get_posts( array( 'post_type' => 'page' ) ); } 

and decided to DRY the code a little gathering these grunts of TDD in a class I can easily re-use here and there.

The solution

I’ve pushed a repository to GitHub to allow for easy Composer usage in future projects of the class; I will be adding more methods I commonly use to the package as the need arises and while I was there I have over-engineered.

The probably over-engineered part

While I do not want to deal with common data providers any more I also would like to make the build process of data providing methods less “write them by hand” and more “write some by hand and reuse”.
Using the same example as the README file I’ve implemented some methods in the class to go from this

/** * @dataProvider valuesAndOddResponses */ public function testIsOdd($value, $response){ $sut = new SomeClass(); $this->assertEquals($response, $sut->isOdd($value)); } public function valuesAndOddResponses(){ return array( array(1, true), array(2, false), array(3, true), array(4, false), array(43, true), array(-1, true), array(-4, false), array(-1.0, true), array(5.0, true), array(8.0, false) ); } /** * @dataProvider valuesAndEvenResponses */ public function testIsEven($value, $response){ $sut = new SomeClass(); $this->assertEquals($response, $sut->isEven($value)); } public function valuesAndEvenResponses(){ return array( array(1, false), array(2, true), array(3, false), array(4, true), array(43, false), array(-1, false), array(-4, true), array(-1.0, false), array(5.0, false), array(8.0, true) ); } 

which works but is tedious, to this

private oddValues = array(1, 3, 43, -1, -1.0, 5.0); private evenValues = array(2, 4, 8.0, -4); public function valuesAndOddResponses(){ return array_merge( PHPUnitDataProvider::wrap($this->oddValues) ->append(true)->provide(), PHPUnitDataProvider::wrap($this->evenValues) ->append(false)->provide() ); } public function valuesAndEvenResponses(){ return array_merge( PHPUnitDataProvider::wrap($this->oddValues) ->append(false)->provide(), PHPUnitDataProvider::wrap($this->evenValues) ->append(true)->provide() ); } /** * @dataProvider valuesAndEvenResponses */ public function testIsOdd($value, $response){ $sut = new SomeClass(); $this->assertEquals($response, $sut->isEven($value)); } /** * @dataProvider valuesAndOddResponses */ public function testIsOdd($value, $response){ $sut = new SomeClass(); $this->assertEquals($response, $sut->isOdd($value)); } 

In such a small example it falls into the overkill category but I feel like it might have a sense in bigger projects. And I haven’t used the expedient of a use statement like

use lucatume\DataProvider\PHPUnitDataProvider as D; public function valuesAndEvenResponses(){ return array_merge( D::wrap($this->oddValues)->append(false)->provide(), D::wrap($this->evenValues)->append(true)->provide() ); } 

I appreciate your input