问题
In PHPUnit it quite easy to assert that two arrays contain the same value:
$this->assertEquals( [1, 2, 3], [1, 2, 3] );
Recent versions of PHP made usage of Iterators and Generators a lot more attractive, and PHP 7.1 introduced the iterable pseudo-type. That means I can write functions to take and return iterable
without binding to the fact I am using a plain old array
or using a lazy Generator
.
How do I assert the return value of functions returning an iterable
? Ideally I could do something like
$this->assertIterablesEqual( ['expected', 'values'], $iterable );
Is there such a function? Alternatively, is there a sane way of testing this that does not involve adding a pile of besides-the-point imperative code to my tests?
回答1:
I think you need to wrap the Iterable first. As an example, a decorator for Iterable can be found in Iterator Garden named ForeachIterator which is decorating anything foreach-able as a Traversable:
$iterator = new ForeachIterator($iterable);
$this->assertEquals( [1, 2, 3], itarator_to_array($iterator));
Take note to the detail, that it would also consider objects Iterable in that test, which is not strict enough for a correct test.
However this should be easy to translate into a private helper method in your test to only turn arrays and traversable object - not non-traversable objects - into an iterator / array and apply the assertion:
private function assertIterablesEqual(array $expected, iterable $actual, $message = '')
{
$array = is_array($actual) ? $actual : iterator_to_array($actual);
$this->assertEquals($expected, $array, $message);
}
This can be further extracted into an assertion class to extend Phpunit itself.
Take note that iterator_to_array
will replace entries with duplicate keys, resulting in an array with the last iteration value of duplicate keys. If you need assertion of iteration keys as well, decorating or change of the traversal method might become necessary.
回答2:
You could use iterator_to_array function, as example:
$expected = [1, 2, 3];
$this->assertEquals( $expected, iterator_to_array($iterable) );
This works for generators also.
Hope this help
来源:https://stackoverflow.com/questions/44591972/testing-iterables-in-phpunit