原文:https://docs.scipy.org/doc/numpy/reference/swig.testing.html
校对:(虚位以待)
为numpy.i SWIG接口文件编写测试是一种组合性头痛。目前,支持12种不同的数据类型,每种类型具有74个不同的参数签名,支持“开箱即用”的总共888个类型映射。这些类型映射中的每一个反过来可能需要几个单元测试,以便验证正确和不正确输入的预期行为。目前,这将导致在进行 测试时在numpy/tools/swig
为了促进这种许多类似的单元测试,采用一些高级编程技术,包括C和SWIG宏以及Python继承。本文档的目的是描述用于验证numpy.i类型映射是否按预期工作的测试基础结构。
支持三个独立的测试框架,分别用于一维,二维和三维数组。对于一维数组,有两个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将确保所有测试软件都已构建,然后运行所有三个测试脚本。
Vector.h是一个C ++头文件,它定义了一个名为TEST_FUNC_PROTOS的C宏,它接受两个参数:TYPE,这是一个数据类型名称unsigned int;和SNAME,这是相同数据类型的短名称,不含空格,例如uint。此宏定义了几个具有前缀SNAME的函数原型,并且至少有一个参数是类型TYPE的数组。具有返回参数的函数返回TYPE值。
numpy.i支持的所有数据类型都将实现TEST_FUNC_PROTOS:
签名 char无符号 charshort无符号 短int无符号 intlong无符号 长long long无符号 长 长floatdouble
Vector.cxx是一个C ++源文件,用于实现Vector.h中指定的每个函数原型的可编译代码。它定义具有相同参数的C宏TEST_FUNCS,其工作方式与TEST_FUNC_PROTOS在Vector.h中相同。TEST_FUNCS针对上述12种数据类型中的每一种实现。
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中的类型映射。
在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中,然后执行。错误和失败被汇总在一起并作为退出参数返回。任何非零结果表明至少一个测试未通过。