Тестирование typemaps numpy.i
Введение
Написание тестов для файла интерфейса numpy.i SWIG — задача с комбинаторной сложностью. В настоящее время поддерживается 12 различных типов данных, каждый с 74 различными сигнатурами аргументов, в общей сложности 888 typemaps поддерживаются «из коробки». Каждый из этих typemaps, в свою очередь, может потребовать несколько модульных тестов для проверки ожидаемого поведения как для корректных, так и для некорректных входных данных. В настоящее время это приводит к выполнению более 1000 отдельных модульных тестов при запуске make test в подкаталоге numpy/tools/swig.
Для облегчения такого большого количества похожих модульных тестов используются некоторые высокоуровневые программирования, включая C и макросы SWIG, а также наследование в Python. Цель данного документа — описать инфраструктуру тестирования, используемую для проверки того, что typemaps numpy.i работают как ожидается.
Организация тестирования
Поддерживаются три независимые тестовые среды для одномерных, двумерных и трехмерных массивов соответственно. Для одномерных массивов существуют два файла C++, заголовок и исходный код, имеющие имена:
Vector.h Vector.cxx
в которых содержатся прототипы и код для различных функций, имеющих одномерные массивы в качестве аргументов. Файл:
Vector.i
является файлом интерфейса SWIG, который определяет модуль Python Vector, который оборачивает функции в Vector.h, используя typemaps в numpy.i, чтобы правильно обрабатывать массивы C.
Makefile вызывает swig для генерации Vector.py и Vector_wrap.cxx, а также выполняет скрипт setup.py, который компилирует Vector_wrap.cxx и связывает вместе модуль расширения _Vector.so или _Vector.dylib, в зависимости от платформы. Этот модуль расширения и файл-прокси Vector.py размещаются в подкаталоге каталога build.
Фактическое тестирование выполняется с помощью скрипта Python с именем:
testVector.py
который использует стандартный модуль Python unittest, который выполняет несколько тестов каждой функции, определенной в Vector.h для каждого поддерживаемого типа данных.
Двумерные массивы тестируются точно так же. Вышеописанное описание применимо, но с заменой Matrix на Vector. Для трехмерных тестов замените Tensor на Vector. Для четырехмерных тестов замените SuperTensor на Vector. Для тестов плоских массивов in-place замените Flat на Vector. В следующих описаниях мы будем ссылаться на тесты Vector, но та же информация применима к тестам Matrix, Tensor и SuperTensor.
Команда make test обеспечит сборку всего тестового программного обеспечения и запустит все три тестовых скрипта.
Файлы заголовков тестирования
Vector.h — это файл заголовка C++, который определяет C-макрос, называемый TEST_FUNC_PROTOS, принимающий два аргумента: TYPE, который представляет собой имя типа данных, например, unsigned int; и SNAME, которое представляет собой короткое имя того же типа данных без пробелов, например, uint. Этот макрос определяет несколько прототипов функций с префиксом SNAME и по крайней мере один аргумент, являющийся массивом типа TYPE. Функции, имеющие возвращаемые аргументы, возвращают значение TYPE.
TEST_FUNC_PROTOS затем реализуется для всех типов данных, поддерживаемых numpy.i:
signed charunsigned charshortunsigned shortintunsigned intlongunsigned longlong longunsigned long longfloatdouble
Файлы исходного кода тестирования
Vector.cxx — это файл исходного кода C++, который реализует компилируемый код для каждого из прототипов функций, указанных в Vector.h. Он определяет C-макрос TEST_FUNCS, который имеет те же аргументы и работает так же, как TEST_FUNC_PROTOS в Vector.h. TEST_FUNCS реализуется для каждого из 12 типов данных, как и выше.
Тестирование файлов интерфейса SWIG
Vector.i — это файл интерфейса SWIG, который определяет модуль Python Vector. Он следует соглашениям для использования numpy.i как описано в этой главе. Он определяет макрос SWIG %apply_numpy_typemaps, имеющий один аргумент TYPE. Он использует директиву SWIG %apply для применения предоставленных typemaps к сигнатурам аргументов, найденных в Vector.h. Этот макрос затем реализуется для всех типов данных, поддерживаемых numpy.i. Затем он выполняет %include "Vector.h" для обертывания всех прототипов функций в Vector.h с использованием typemaps в numpy.i.
Тестирование скриптов Python
После использования make для построения тестовых модулей расширения, можно запустить testVector.py для выполнения тестов. Как и в других скриптах, использующих unittest для облегчения модульного тестирования, testVector.py определяет класс, наследуемый от unittest.TestCase:
class VectorTestCase(unittest.TestCase):
Однако этот класс не выполняется напрямую. Вместо этого он служит базовым классом для нескольких других классов Python, каждый из которых специфичен для определенного типа данных. Класс VectorTestCase хранит две строки для информации о типе данных:
- self.typeStr
-
Строка, которая соответствует одному из префиксов
SNAME, используемых вVector.hиVector.cxx. Например,"double". - self.typeCode
-
Короткая (обычно односимвольная) строка, которая представляет тип данных в numpy и соответствует
self.typeStr. Например, еслиself.typeStrявляется"double", тоself.typeCodeдолжно быть"d".
Каждый тест, определенный классом VectorTestCase, извлекает функцию Python, которую он пытается проверить, обращаясь к словарю модуля Vector:
length = Vector.__dict__[self.typeStr + "Length"]
В случае тестов с двойной точностью это вернет функцию Python Vector.doubleLength.
Затем мы определяем новый класс тестового случая для каждого поддерживаемого типа данных с коротким описанием, например:
class doubleTestCase(VectorTestCase):
def __init__(self, methodName="runTest"):
VectorTestCase.__init__(self, methodName)
self.typeStr = "double"
self.typeCode = "d"
Каждый из этих 12 классов собирается в unittest.TestSuite, который затем выполняется. Ошибки и сбои суммируются и возвращаются в качестве аргумента выхода. Любое ненулевое значение указывает на то, что по крайней мере один тест не прошел.
© 2005–2024 NumPy Developers
Licensed under the 3-clause BSD License.
https://numpy.org/doc/2.0/reference/swig.testing.html