2020年11月27日 / 293次阅读 / Last Modified 2020年12月4日
ctypes,unittest
如果你也像我一样,日常的开发工作是以python为主,C为辅;或者你觉得用C语言的工具来做C函数的单元测试太麻烦。。你可以试着用Python来完成C函数的单元测试。
Python的定位是应用的快速开发,牺牲一定性能;C的定位是高性能,但不适合用来开发应用,效率太低。它们两者是可以结合的,用Python来做C函数的单元测试,只是结合的一个方便。
Python自带unittest单元测试框架,用来测试C函数,也非常方便。
sort.c中有两个C函数:
void bubble(int a[], int n)
{
int i,j;
for (i=0; i<n-1; ++i){
for (j=0; j<n-i-1; ++j){
if (a[j] > a[j+1])
a[j] ^= a[j+1] ^= a[j] ^= a[j+1];
}
}
}
void select(int a[], int n)
{
int i,j,k;
for (i=n; i>1; --i){
k = 0;
for (j=1; j<i; ++j){
if (a[k] < a[j])
k = j;
}
if (k != j-1)
a[k] ^= a[j-1] ^= a[k] ^= a[j-1];
}
}
以上代码分别是冒泡排序和选择排序,两个经典的排序算法。
下面是用python的unittest写的用来测试这两个函数的测试集:
class test_sort_c(unittest.TestCase):
@classmethod
def setUpClass(cls):
print('\n# sort.c:')
shell('gcc -W -fPIC -shared -O3 sort.c -o sort.so')
cls.sort = ctypes.CDLL('./sort.so')
@classmethod
def tearDownClass(cls):
os.remove('sort.so')
def get_sort(self):
return test_sort_c.sort
def setUp(self):
self.a01 = (1,2,3,4,5,6,7,8,9)
self.ca01 = (ctypes.c_int*9)(*self.a01)
self.dca01 = ctypes.byref(self.ca01)
self.a02 = (9,8,7,6,5,4,3,2,1)
self.ca02 = (ctypes.c_int*9)(*self.a02)
self.dca02 = ctypes.byref(self.ca02)
self.a03 = (6,1,9,3,7,-2,5,-4,0,8,2)
self.ca03 = (ctypes.c_int*len(self.a03))(*self.a03)
self.dca03 = ctypes.byref(self.ca03)
def tearDown(self):
...
def test_bubble(self):
sort = self.get_sort()
sort.bubble(self.dca01, 9)
self.assertEqual(tuple(self.ca01), self.a01)
sort.bubble(self.dca02, 0)
self.assertEqual(tuple(self.ca02), self.a02)
sort.bubble(self.dca02, -1)
self.assertEqual(tuple(self.ca02), self.a02)
sort.bubble(self.dca02, 9)
self.assertEqual(tuple(self.ca02), self.a01)
sort.bubble(self.dca03, len(self.a03))
self.assertEqual(list(self.ca03), sorted(self.a03))
def test_select(self):
sort = self.get_sort()
sort.select(self.dca01, 9)
self.assertEqual(tuple(self.ca01), self.a01)
sort.select(self.dca02, 0)
self.assertEqual(tuple(self.ca02), self.a02)
sort.select(self.dca02, -1)
self.assertEqual(tuple(self.ca02), self.a02)
sort.select(self.dca02, 9)
self.assertEqual(tuple(self.ca02), self.a01)
sort.select(self.dca03, len(self.a03))
self.assertEqual(list(self.ca03), sorted(self.a03))
在setUpClass中,将sort.c编译成sort.so,并加载到类变量sort。setUp用来准备测试数据,给两个test_开头的单元测试函数。测试结束后,通过tearDownClass函数删除sort.so文件。
测试很成功!这种用法的本质,就是通过python的ctypes模块来调用C函数,已达到C函数单元测试的目的。
关于用python来做C语言的单元测试框架,网上能找到的资料不多,这个还不错:https://ep2016.europython.eu/media/conference/slides/writing-unit-tests-for-c-code-in-python.html,这是2016年欧洲python开会时,一个人的演讲ppt,就是在将用python给C语言做单元测试的好处以及方法(cffi)。
-- EOF --
本文链接:https://www.pynote.net/archives/2923
《用Python做C函数的单元测试》有1条留言
前一篇:7bit压缩编码
后一篇:用flake8检查python代码
Ctrl+D 收藏本页
©Copyright 麦新杰 Since 2019 Python笔记
遇到了一次这样的case:单独执行某个单元测试,成功;测试整个suite,失败。原因是C语言写的代码的某些内存越界错误,在程序动态执行过程中,表现不一致。 [ ]