用Python做C函数的单元测试

2020年11月27日 / 24次阅读 / Last Modified 2020年12月4日
ctypesunittest

如果你也像我一样,日常的开发工作是以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 unittest框架的使用。

测试很成功!这种用法的本质,就是通过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条留言

电子邮件地址不会被公开。 必填项已用*标注

  • 麦新杰

    遇到了一次这样的case:单独执行某个单元测试,成功;测试整个suite,失败。原因是C语言写的代码的某些内存越界错误,在程序动态执行过程中,表现不一致。 [回复]


前一篇:
后一篇:

More


©Copyright 麦新杰 Since 2019 Python笔记

go to top