Как я могу проверить, что ключ НЕ существует на разных уровнях многомерного массива с использованием поставщиков данных? - PullRequest
0 голосов
/ 24 мая 2018

У меня есть метод, который создает большой многомерный массив.Я пытаюсь запустить серию модульных тестов по этому методу.Я пытаюсь сделать как положительные тесты (тестирование, что определенные ключи массива установлены), так и отрицательные тесты (тестирование, что определенные ключи массива отсутствуют).Проблема в том, что для настройки объекта требуется много кода, и существует множество различных аргументов, которые этот метод принимает, и которые я хочу протестировать.По этим причинам я хочу использовать провайдеров данных для запуска серии тестов метода.Таким образом, я мог бы настроить объект один раз и использовать поставщик данных для получения аргументов массива и ожидаемых значений массива.

Я могу выполнить положительные тесты, вызвав $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'].Если я выполню вышеуказанный тест, он проверит, что «d» не существует в $array['a'], что не то, что я хочу. Что может быть хорошим способом структурировать мои тесты для динамической проверки того, что мои ключи не существуют в разных частях массива?

Я думал о том, чтобы мой поставщик данных возвратил четвертый ключ, которыйродительский ключ для использования.Вот так:

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 голосов
/ 27 мая 2018

Насколько я знаю, Phpunit не предлагает рекурсивное утверждение для ключа массива.

Вы можете расширить Phpunit своими собственными утверждениями, но я бы начал с легкости и добавил бы частный вспомогательный метод к тесту.случай, который возвращает bool независимо от того, является ли массив рекурсивным в качестве ключа (проверьте существующий материал вопросов и ответов, например Поиск ключа в массиве, рекурсивно и другие о том, как проверять массив для ключа рекурсивно), изатем сделайте утверждение для ложного типа:

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

, просто имейте в виду, когда вы пишете код для поддержки ваших тестов, чтобы сделать его довольно тупым (а иногда вам нужно также тестировать вспомогательные подпрограммы, чтобываши тесты не лгут вам об ошибках).


Перекрестная ссылка

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...