用C语言对Gtk+应用进行功能测试
2023-03-09 22:07:18 时间
这个简单教程教你如何测试你应用的功能。
自动化测试用来保证你程序的质量以及让它以预想的运行。单元测试只是检测你算法的某一部分,而并不注重各组件间的适应性。这就是为什么会有功能测试,它有时也称为集成测试。
功能测试简单地与你的用户界面进行交互,无论它是网站还是桌面应用。为了展示功能测试如何工作,我们以测试一个 Gtk+ 应用为例。为了简单起见,这个教程里,我们使用 Gtk+ 2.0 教程的示例。
基础设置
对于每一个功能测试,你通常需要定义一些全局变量,比如 “用户交互时延” 或者 “失败的超时时间”(也就是说,如果在指定的时间内一个事件没有发生,程序就要中断)。
- #define TTT_FUNCTIONAL_TEST_UTIL_IDLE_CONDITION(f) ((TttFunctionalTestUtilIdleCondition)(f))
- #define TTT_FUNCTIONAL_TEST_UTIL_REACTION_TIME (125000)
- #define TTT_FUNCTIONAL_TEST_UTIL_REACTION_TIME_LONG (500000)
- typedef gboolean (*TttFunctionalTestUtilIdleCondition)(gpointer data);
- struct timespec ttt_functional_test_util_default_timeout = {
- 20,
- 0,
- };
现在我们可以实现我们自己的超时函数。这里,为了能够得到期望的延迟,我们采用 usleep 函数。
- void
- ttt_functional_test_util_reaction_time()
- {
- usleep(TTT_FUNCTIONAL_TEST_UTIL_REACTION_TIME);
- }
- void
- ttt_functional_test_util_reaction_time_long()
- {
- usleep(TTT_FUNCTIONAL_TEST_UTIL_REACTION_TIME_LONG);
- }
直到获得控制状态,超时函数才会推迟执行。这对于一个异步执行的动作很有帮助,这也是为什么采用这么长的时延。
- void
- ttt_functional_test_util_idle_condition_and_timeout(
- TttFunctionalTestUtilIdleCondition idle_condition,
- struct timespec *timeout,
- pointer data)
- {
- struct timespec start_time, current_time;
- clock_gettime(CLOCK_MONOTONIC,
- &start_time);
- while(TTT_FUNCTIONAL_TEST_UTIL_IDLE_CONDITION(idle_condition)(data)){
- ttt_functional_test_util_reaction_time();
- clock_gettime(CLOCK_MONOTONIC,
- ¤t_time);
- if(start_time.tv_sec + timeout->tv_sec < current_time.tv_sec){
- break;
- }
- }
- ttt_functional_test_util_reaction_time();
- }
与图形化用户界面交互
为了模拟用户交互的操作, Gdk 库 为我们提供了一些需要的函数。要完成我们的工作,我们只需要如下 3 个函数:
- gdk_display_warp_pointer()
- gdk_test_simulate_button()
- gdk_test_simulate_key()
举个例子,为了测试按钮点击,我们可以这么做:
- gboolean
- ttt_functional_test_util_button_click(GtkButton *button)
- {
- GtkWidget *widget;
- GdkWindow *window;
- gint x, y;
- gint origin_x, origin_y;
- if(button == NULL ||
- !GTK_IS_BUTTON(button)){
- return(FALSE);
- }
- widget = button;
- if(!GTK_WIDGET_REALIZED(widget)){
- ttt_functional_test_util_reaction_time_long();
- }
- /* retrieve window and pointer position */
- gdk_threads_enter();
- window = gtk_widget_get_window(widget);
- x = widget->allocation.x + widget->allocation.width / 2.0;
- y = widget->allocation.y + widget->allocation.height / 2.0;
- gdk_window_get_origin(window, &origin_x, &origin_y);
- gdk_display_warp_pointer(gtk_widget_get_display(widget),
- gtk_widget_get_screen(widget),
- origin_x + x, origin_y + y);
- gdk_threads_leave();
- /* click the button */
- ttt_functional_test_util_reaction_time();
- gdk_test_simulate_button(window,
- x,
- y,
- 1,
- GDK_BUTTON1_MASK,
- GDK_BUTTON_PRESS);
- ttt_functional_test_util_reaction_time();
- gdk_test_simulate_button(window,
- x,
- y,
- 1,
- GDK_BUTTON1_MASK,
- GDK_BUTTON_RELEASE);
- ttt_functional_test_util_reaction_time();
- ttt_functional_test_util_reaction_time_long();
- return(TRUE);
- }
我们想要保证按钮处于激活状态,因此我们提供一个空闲条件函数:
- gboolean
- ttt_functional_test_util_idle_test_toggle_active(
- GtkToggleButton **toggle_button)
- {
- gboolean do_idle;
- do_idle = TRUE;
- gdk_threads_enter();
- if(*toggle_button != NULL &&
- GTK_IS_TOGGLE_BUTTON(*toggle_button) &&
- gtk_toggle_button_get_active(*toggle_button)){
- do_idle = FALSE;
- }
- gdk_threads_leave();
- return(do_idle);
- }
测试场景
因为这个 Tictactoe 程序非常简单,我们只需要确保点击了一个 GtkToggleButton 按钮即可。一旦该按钮肯定进入了激活状态,功能测试就可以执行。为了点击按钮,我们使用上面提到的很方便的 util 函数。
如图所示,我们假设,填满***行,玩家 A 就赢,因为玩家 B 没有注意,只填充了第二行。
- GtkWindow *window;
- Tictactoe *ttt;
- void*
- ttt_functional_test_gtk_main(void *)
- {
- gtk_main();
- pthread_exit(NULL);
- }
- void
- ttt_functional_test_dumb_player_b()
- {
- GtkButton *buttons[3][3];
- guint i;
- /* to avoid race-conditions copy the buttons */
- gdk_threads_enter();
- memcpy(buttons, ttt->buttons, 9 * sizeof(GtkButton *));
- gdk_threads_leave();
- /* TEST 1 - the dumb player B */
- for(i = 0; i < 3; i++){
- /* assert player A clicks the button successfully */
- if(!ttt_functional_test_util_button_click(buttons[0][i])){
- exit(-1);
- }
- functional_test_util_idle_condition_and_timeout(
- ttt_functional_test_util_idle_test_toggle_active,
- ttt_functional_test_util_default_timeout,
- &buttons[0][i]);
- /* assert player B clicks the button successfully */
- if(!ttt_functional_test_util_button_click(buttons[1][i])){
- exit(-1);
- }
- functional_test_util_idle_condition_and_timeout(
- ttt_functional_test_util_idle_test_toggle_active,
- ttt_functional_test_util_default_timeout,
- &buttons[1][i]);
- }
- }
- int
- main(int argc, char **argv)
- {
- pthread_t thread;
- gtk_init(&argc, &argv);
- /* start the tictactoe application */
- window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- ttt = tictactoe_new();
- gtk_container_add(window, ttt);
- gtk_widget_show_all(window);
- /* start the Gtk+ dispatcher */
- pthread_create(&thread, NULL,
- ttt_functional_test_gtk_main, NULL);
- /* launch test routines */
- ttt_functional_test_dumb_player_b();
- /* terminate the application */
- gdk_threads_enter();
- gtk_main_quit();
- gdk_threads_leave();
- return(0);
- }
(题图:opensource.com)
相关文章
- LibreOffice 7.5 发布:漂亮的新应用图标和酷炫功能
- elementary OS 7 发布
- Windows 应用兼容层 Wine 8.1 发布:默认启用“Windows 10”前缀
- 微软正测试新功能:当 Windows 11 有新的小组件可用时会提醒通知
- 解析分布式存储选型和应用九个典型问题
- ClickHouse在自助行为分析场景的实践应用
- Chrome DevTools 远程调试安卓网页的原理
- Uni-app + Vue3 页面如何跳转及传参?
- 微软证实系统还原点会损坏 Windows 11 22H2 版本应用程序
- 巧用 Transition 实现短视频 APP 点赞动画
- 初学者试试,HarmonyOS应用开发者基础认证
- 媒体实测微软 Windows 开发工具包 2023:存在不兼容 HDR 显示器、某些应用无法运行等问题
- 快速了解Navigator API SetAppBadge
- 微软 Windows 11 Dev 预览版 Build 25276 发布,应用兼容问题对话框 UI 改进
- 基于Next.js、Prisma、Postgres和Fastfy构建全栈APP
- 开始菜单搜索框变圆角,微软 Windows 11 Beta 预览版 22621.1095 和 22623.1095 发布
- 2022-2023 十大应用开发趋势
- 观远数据发布业内首部《移动BI白皮书》,深入业务数字化场景重新定义移动BI
- Windows 10 学院:不借助第三方工具如何卸载 Windows 10 预装应用
- 正处高质量发展期,我国大数据产业突破1.3万亿元