动态库是在程序运行时才被载入的,可以大大减小程序体积,提高程序运行速度的链接库。在Linux下,我们可以使用一些工具来测试动态库接口,以确保其正确性和可靠性。本文将介绍一些常用的Linux下动态库接口测试工具和测试方法,并提供一些简易指南,帮助初学者更好地进行动态库接口测试。
一、动态库接口测试概述
动态库接口测试是测试动态库是否能够正确地链接和使用,以及是否具有预期的功能和行为。动态库接口包括函数名、参数类型、返回类型等,它们必须与其他应用程序或库的接口严格匹配,否则就会出现链接错误或运行时错误。
动态库接口测试的目的是验证应用程序或库能够成功地调用动态库的接口,并且处理不同的输入和异常情况时能够正确地响应。测试用例应涵盖所有的接口函数和参数类型,并包括相关的边界条件和异常情况。
二、常用的动态库接口测试工具
1. ldd
ldd命令用来列出一个动态库所依赖的其他库,可以用来检查动态库的依赖关系和版本信息,以保证程序能够正确链接并运行。
例如:
“`
$ ldd libtest.so
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007fd40a29d000)
libm.so.6 => /lib64/libm.so.6 (0x00007fd409f2f000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fd409d17000)
libc.so.6 => /lib64/libc.so.6 (0x00007fd40994e000)
/lib64/ld-linux-x86-64.so.2 (0x00007fd40a6bb000)
“`
2. nm
nm命令用来显示动态库中包含的符号列表,包括函数名、变量名和其他符号等,可以用来检查动态库中的接口是否正确定义和实现。
例如:
“`
$ nm libtest.so
U _ZNSt7__cxx1112basic_stringIcSt11char_trtsIcESaIcEEC1Ev
00000000000010e0 T func1
0000000000001140 T func2
U puts@@GLIBC_2.2.5
U strlen@@GLIBC_2.2.5
U std::__cxx11::basic_string, std::allocator >::size() const
“`
3. objdump
objdump命令用于查看二进制文件的指令、符号、重定向表和其他信息。可以用objdump命令来检查动态库的接口是否正确实现、是否存在潜在的安全漏洞等。
例如:
“`
$ objdump -T libtest.so
libtest.so: file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000000 D *UND* 0000000000000000 GLIBC_2.2.5 puts
0000000000000000 D *UND* 0000000000000000 GLIBC_2.2.5 strlen
0000000000000000 w D *UND* 0000000000000000 __gmon_start__
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __libc_start_mn
0000000000001020 g DF .text 0000000000000020 Base func1
0000000000001080 g DF .text 0000000000000020 Base func2
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __cxa_finalize
“`
4. gdb
gdb是GNU调试器,可以用来调试动态库中的函数,查找并修复相关的错误和故障。
例如:
“`
$ gdb ./test
(gdb) b func1
(gdb) r
(gdb) step
(gdb) p ret
$1 = 10
(gdb) step
(gdb) p ret
$2 = 20
(gdb) q
“`
五、动态库接口测试方法
动态库接口测试方法包括手动测试和自动测试两种。手动测试是通过手工执行测试用例来检查动态库接口的正确性和可靠性;而自动测试则是通过一些工具来自动化执行测试用例和检查测试结果。
1. 手动测试
手动测试需要编写测试用例并对其进行手工执行,以模拟不同的输入和异常情况,并检查测试结果是否与预期相符。
例如:
测试用例1:测试func1函数的功能和正确性
“`
#include
#include “libtest.h”
int mn() {
int ret1, ret2, expect1, expect2;
ret1 = func1(2, 3);
expect1 = 5;
if (ret1 != expect1) {
printf(“func1 test fled: expect %d, but got %d\n”, expect1, ret1);
}
ret2 = func1(-2, 3);
expect2 = 1;
if (ret2 != expect2) {
printf(“func1 test fled: expect %d, but got %d\n”, expect2, ret2);
}
return 0;
}
“`
测试用例2:测试func2函数的功能和正确性
“`
#include
#include “libtest.h”
int mn() {
const char* str = “hello”;
int ret1, ret2, expect1, expect2;
ret1 = func2(str);
expect1 = 5;
if (ret1 != expect1) {
printf(“func2 test fled: expect %d, but got %d\n”, expect1, ret1);
}
ret2 = func2(NULL);
expect2 = -1;
if (ret2 != expect2) {
printf(“func2 test fled: expect %d, but got %d\n”, expect2, ret2);
}
return 0;
}
“`
2. 自动测试
自动测试需要使用一些测试框架来自动化执行测试用例和检查测试结果。常用的测试框架包括Google Test、CUnit等。
例如:
使用Google Test测试框架进行自动测试
“`
#include
#include “libtest.h”
TEST(Func1Test, PositiveTest) {
EXPECT_EQ(5, func1(2, 3));
}
TEST(Func1Test, NegativeTest) {
EXPECT_EQ(1, func1(-2, 3));
}
TEST(Func2Test, PositiveTest) {
const char* str = “hello”;
EXPECT_EQ(5, func2(str));
}
TEST(Func2Test, NegativeTest) {
EXPECT_EQ(-1, func2(NULL));
}
int mn(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
“`
六、
动态库接口测试是确保动态库正确性和可靠性的重要步骤。在Linux下,我们可以使用一些工具来测试动态库接口,包括ldd、nm、objdump和gdb等。同时,手动测试和自动测试也是动态库接口测试的两种常用方法,可以根据不同的需求选择适合自己的测试方法。
相关问题拓展阅读:
- 请教关于android linux动态库.so的加载调用
- 如何判断linux 动态库调用
请教关于android linux动态库.so的加载调用
1、 .so动态库的生成
可使用gcc或者g++编译器生成动态库文件(此处以g++编译器为例)
g++ -shared -fPIC -c XXX.cpp
g++ -shared -fPIC -o XXX.so XXX.o
2、 .so动态库的动态调用接口函数说明
动态库的调用关系可以在需要调用动态库的程序编译时,通过g++的-L和-l命令来指定。例如:程序test启动时需要加载目录/root/src/lib中的libtest_so1.so动态库,编译命令可照如下编写执行:
g++ -g -o test test.cpp –L/root/src/lib –ltest_so1
(此处,我们重点讲解动态库的动态调用的方法,关于静态的通过g++编译命令调用的方式不作详细讲解,具体相关内容可上网查询)
Linux下,提供专门的一组API用于完成打开动态库慧芦,查找符号,处理出错,关闭动态库等功能。
下面对这些接口函数逐一介绍(调用这些接口时,需引用头文件#include ):
1)dlopen
函数原型:void *dlopen(const char *libname,int flag);
功能描述:dlopen必须在dlerror,dlsym和dlclose之前调用,表示要将库装载到内存,准备使用。如果要装载的库依赖于其它库,必须首先装载依赖库。如果dlopen操作失败,返回NULL值;如果库已经被装载过,则dlopen会返回同样的句柄。
参数中的libname一般是库的全路径,这样dlopen会直接装载该文件;如果只是指定了库名称,在dlopen会按照下面的机制去搜寻:
a.根据环境变量LD_LIBRARY_PATH查找
b.根据/etc/ld.so.cache查找
c.查找依次在/lib和/usr/lib目录查找。
flag参数表示处理未定义函数的方式,可以使用RTLD_LAZY或RTLD_NOW。RTLD_LAZY表示暂时不去处理未定义函数,迅搜先把库装载到内存,等用到没定义的函数再说;RTLD_NOW表示马上检查是否存在未定义的函数,若存在,则dlopen以失败告终。
2)dlerror
函数原型:char *dlerror(void);
功能描述:dlerror可以获得最近一次dlopen,dlsym或dlclose操作的错误信息,返回NULL表示无错误。dlerror在返回错误信息的同时,也会清除错误信息。
3)dlsym
函数原型:void *dlsym(void *handle,const char *symbol);
功能描述:在dlopen之后,库被装载到内存。dlsym可以获得指定函数(symbol)在内前昌带存中的位置(指针)。如果找不到指定函数,则dlsym会返回NULL值。但判断函数是否存在更好的方法是使用dlerror函数,
4)dlclose
函数原型:int dlclose(void *);
功能描述:将已经装载的库句柄减一,如果句柄减至零,则该库会被卸载。如果存在析构函数,则在dlclose之后,析构函数会被调用。
3、 普通函数的调用
此处以源码实例说明。各源码文件关系如下:
test_so1.h和test_so1.cpp生成test_so1.so动态库。
test_so2.h和test_so2.cpp生成test_so2.so动态库。
test_dl.cpp生成test_dl可执行程序,test_dl通过dlopen系列等API函数,并使用函数指针以到达动态调用不同so库中test函数的目的。
如何判断linux 动态库调用
创建静态库:
ar -rcs test.a *.o
查看静态库:
ar -tv test.a
解压静态库:
ar -x test.a
查看程序依赖的动态库:
readelf -a xxx|grep library
如:可以看到,下面的交饥贺叉程序hello执行依赖于如下两个动态库。
rebi@ubuntu:~/test$ arm-none-linux-gnueabi-readelf -a hello|grep “library”
0x(NEEDED)Shared library:
0x(NEEDED)Shared library:
rebi@ubuntu:~/test$
或者迹哗:readelf -l hello 即可。
nm xxx 查看符号
关于linux测试动态库接口的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。