如何使用数据提供程序测试多维数组的不同级别上是否存在密钥?

时间:2018-05-24 06:26:41

标签: php unit-testing phpunit

我有一个创建大型多维数组的方法。我正在尝试对此方法进行一系列单元测试。我正在尝试做两个正面测试(测试某些数组键设置)和负面测试(测试某些数组键不存在)。问题是设置对象需要很多代码,并且这个方法接受了许多我想要测试的不同参数。出于这些原因,我想使用data providers对该方法进行一系列测试。这样我就可以设置一次对象并使用数据提供程序来获取数组参数和预期的数组值。

我可以通过调用$this->assertArraySubset()并在数据提供程序中包含预期的数组结构来进行肯定测试。但我想不出一个测试某些数组键不存在的好方法(我的否定测试),因为这些数组键位于数组的不同级别。

以下是我的代码示例,以便您可以看到我正在处理的内容:

<?php

class MyClassTest {

    public function providerForFunctionThatCreatesArray() {
        return [
            [
                '{foo:bar}', # some data returned by service A
                '{foo:baz}', # some data returned by service B
                'c' # checking that this key does not exist in the array
            ],
            [
                '{foo:barbaz}',
                '{foo:bazbar}',
                'd' # I also want to check that this key does not exist but in a different level of the array (i.e. $array['b'])
            ],

        ]
    }

    /**
     * @dataProvider providerForFunctionThatCreatesArray
     */
    public function testFunctionThatCreatesArray($dataFromServiceA, $dataFromServiceB, $expectedKeyNotExists) {

        $serviceA = $this
            ->getMockBuilder(ServiceA::class)
            ->setMethods(['get_data'])
            ->getMock();
        $serviceA->expects($this->any())->method('get_data')->willReturnValue($dataFromServiceA);

        $serviceB = $this
            ->getMockBuilder(ServiceB::class)
            ->setMethods(['get_data'])
            ->getMock();
        $serviceB->expects($this->any())->method('get_data')->willReturnValue($dataFromServiceB);
        $myClass = new MyClass($serviceA, $serviceB);

        $array = $myClass->functionThatCreatesArray();

        // This is the function that checks that keys do not exist in the array
        $this->assertArrayNotHasKey($expectedKeyNotExists, $array['a']);
    }
}

{foo:...}内容是我的函数使用的某些服务返回的数据。不同的值会影响我的函数创建的数组。我为这些服务创建了模拟,并使用数据提供程序强制服务返回的值。

如您所见,我的数据提供程序还返回一个键作为我的测试函数的第三个参数($expectedKeyNotExists)。这是我正在检查的关键字在我的数组中不存在。但是,d密钥是我想要在我的数组的不同部分检查的密钥,例如$array['b']而不是$array['a']。如果我运行上述测试,它将检查$array['a']中不存在'd',这不是我想要的。 构建我的测试以动态检查我的密钥在数组的不同部分中是否存在的好方法是什么?

我想过让我的数据提供者返回第四个密钥,这是要使用的父密钥。像这样:

return [
    [
        '{foo:bar}', # some data returned by service A
        '{foo:baz}', # some data returned by service B
        'c', # checking that this key does not exist in the array   
        'a' # parent key
    ],
    [
        '{foo:barbaz}', # some data returned by service A
        '{foo:bazbar}', # some data returned by service B
        'd', # checking that this key does not exist in the array   
        'b' # parent key
    ]
]

然后我可以像这样做我的测试:

public function testFunctionThatCreatesArray($dataFromServiceA, $dataFromServiceB, $expectedKeyNotExists, $parentKey) {
    // ... snip ...
    $this->assertArrayNotHasKey($expectedKeyNotExists, $array[$parentKey]);
}

上述方法的问题在于,在检查阵列的不同级别的键时,它不是很灵活。例如,如果我想检查$array['a']['e']['f']$array['a']['g']['h']处不存在的密钥该怎么办。

1 个答案:

答案 0 :(得分:2)

据我所知,Phpunit不会递归地提供数组键的断言。

您可以使用自己的断言扩展Phpunit,但我会轻易开始并向测试用例添加一个私有帮助器方法,该方法返回一个bool,无论该数组是否为递归键(检查现有的Q&amp; A材料,如{ {3}}和其他人如何递归地检查数组中的键,然后做一个假的断言,如:

$this->assertFalse(
    $this->arrayHasKeyRecursive($array, $expected), 
    "key must not exist"
);

当你编写代码来支持你的测试时,请记住这一点,使它变得非常愚蠢(有时候你需要将helper例程放在测试中,这样你的测试就不会对你造成错误)。

交叉参考