Testing the numpy.i Typemaps¶
Introduction¶
为numpy.i
SWIG接口文件编写测试是一种组合性头痛。目前,支持12种不同的数据类型,每种类型具有74个不同的参数签名,支持“开箱即用”的总共888个类型映射。这些类型映射中的每一个反过来可能需要几个单元测试,以便验证正确和不正确输入的预期行为。目前,这将导致在进行 测试
时在numpy/tools/swig
为了促进这种许多类似的单元测试,采用一些高级编程技术,包括C和SWIG宏以及Python继承。本文档的目的是描述用于验证numpy.i
类型映射是否按预期工作的测试基础结构。
Testing Organization¶
支持三个独立的测试框架,分别用于一维,二维和三维数组。对于一维数组,有两个C ++文件,一个头和一个源,命名为:
Vector.h
Vector.cxx
其包含用于具有一维数组作为函数参数的各种函数的原型和代码。文件:
Vector.i
is a SWIG interface file that defines a python module Vector
that wraps the functions in Vector.h
while utilizing the typemaps in numpy.i
to correctly handle the C arrays.
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
。对于平面原位数组测试,用Flat
替换Vector
。对于以下描述,我们将引用Vector
测试,但相同的信息适用于Matrix
,Tensor
和SuperTensor
命令make test
将确保所有测试软件都已构建,然后运行所有三个测试脚本。
Testing Header Files¶
Vector.h
是一个C ++头文件,它定义了一个名为TEST_FUNC_PROTOS
的C宏,它接受两个参数:TYPE
,这是一个数据类型名称unsigned int
;和SNAME
,这是相同数据类型的短名称,不含空格,例如uint
。此宏定义了几个具有前缀SNAME
的函数原型,并且至少有一个参数是类型TYPE
的数组。具有返回参数的函数返回TYPE
值。
numpy.i
支持的所有数据类型都将实现TEST_FUNC_PROTOS
:
签名 char
无符号 char
short
无符号 短
int
无符号 int
long
无符号 长
long long
无符号 长 长
float
double
Testing Source Files¶
Vector.cxx
是一个C ++源文件,用于实现Vector.h
中指定的每个函数原型的可编译代码。它定义具有相同参数的C宏TEST_FUNCS
,其工作方式与TEST_FUNC_PROTOS
在Vector.h
中相同。TEST_FUNCS
针对上述12种数据类型中的每一种实现。
Testing SWIG Interface Files¶
Vector.i
是一个定义python模块Vector
的SWIG接口文件。它遵循本章中所述的使用numpy.i
的约定。它定义了具有单个参数TYPE
的SWIG宏%apply_numpy_typemaps
。它使用SWIG指令%apply
将提供的类型映射应用于Vector.h
中的参数签名。然后对由numpy.i
支持的所有数据类型实现此宏。然后,它会在Vector.h
中包含所有的函数原型,%include “Vector.h”使用
numpy.i
中的类型映射。
Testing Python Scripts¶
在make
用于构建测试扩展模块后,可以运行testVector.py
来执行测试。与使用unittest
以促进单元测试的其他脚本一样,testVector.py
定义继承自unittest.TestCase
的类:
class VectorTestCase(unittest.TestCase):
但是,这个类不是直接运行的。相反,它用作几个其他Python类的基类,每个特定于特定数据类型。VectorTestCase
类存储两个用于键入信息的字符串:
- self.typeStr
- 与
Vector.h
和Vector.cxx
中使用的SNAME
前缀之一匹配的字符串。例如,"double"
。- self.typeCode
- 表示numpy中的数据类型的短(通常为单字符)字符串,对应于
self.typeStr
。例如,如果self.typeStr
是"double"
,则self.typeCode
应为"d"
。
由VectorTestCase
类定义的每个测试通过访问Vector
模块的字典来提取它试图测试的python函数:
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
中,然后执行。错误和失败被汇总在一起并作为退出参数返回。任何非零结果表明至少一个测试未通过。