这个简单的教程教您如何测试应用程序的功能。自动化测试用于确保程序的质量并使其按预期工作。单元测试只测试你算法的某一部分,并不关注组件之间的适配性。这就是为什么会有功能测试,有时也称为集成测试。功能测试只是与您的用户界面交互,无论是网站还是桌面应用程序。为了展示功能测试的工作原理,让我们以Gtk+应用程序为例进行测试。为简单起见,在本教程中,我们使用Gtk+2.0教程中的示例。基本设置对于每个功能测试,通常需要定义一些全局变量,例如“用户交互延迟”或“失败超时”(即如果某个事件在指定时间内没有发生,程序将被终止)。#defineTTT_FUNCTIONAL_TEST_UTIL_IDLE_CONDITION(f)((TttFunctionalTestUtilIdleCondition)(f))#defineTTT_FUNCTIONAL_TEST_UTIL_REACTION_TIME(125000)#defineTTT_FUNCTIONAL_TEST_UTIL_REACTION_TIME_LONG(500000)typedefgboolean(*TttFunctionalTestUtilIdleCondition)(gpointerdata);structtimespecttt_functional_test_util_default_timeout={20,0,};现在我们可以实现我们自己的超时函数.在这里,为了获得所需的延迟,我们使用usleep函数。voidttt_functional_test_util_reaction_time(){usleep(TTT_FUNCTIONAL_TEST_UTIL_REACTION_TIME);}voidttt_functional_test_util_reaction_time_long(){usleep(TTT_FUNCTIONAL_TEST_UTIL_REACTION_TIME_LONG);}超时函数不会延迟执行,直到获得控制状态。这对于异步执行的操作很有帮助,这就是为什么需要这么长的延迟。voidttt_functional_test_util_idle_condition_and_timeout(TttFunctionalTestUtilIdleConditionidle_condition,structtimespec*timeout,pointerdata){structtimespecstart_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_secallocation.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();/*clickthebutton*/ttt_functional_test_util_reaction_time();gdk_test_simulate_button(y,window,x,y1,GDK_BUTTON1_MASK,GDK_BUTTON_PRESS);ttt_functional_test_util_reaction_time();gdk_test_simulate_button(窗口,x,y,1,GDK_BUTTON1_MASK,GDK_BUTTON_RELEASE);ttt_functional_test_util_reaction_time();ttt_functional_test_util_reaction_time_long();ttt_functional_test_util_reaction_time_long();ttt_functional_test_util_reaction_time_long(窗口,x,y,1,GDK_BUTTON1_MASK,GDK_BUTTON_RELEASE);gbooleanttt_functional_test_util_idle_test_toggle_active(GtkToggleButton**toggle_button){gbooleando_idle;do_idle=TRUE;gdk_threads_enter();if(*toggle_button!=NULL&>K_IS_TOGGLE_BUTTON(*toggle_button)&>k_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);}voidttt_functional_test_dumb_player_b(){GtkButton*buttons[3][3];guinti;/*避免竞争条件复制按钮*/gdk_threads_enter();memcpy(buttons,ttt->buttons,9*sizeof(GtkButton*));gdk_threads_leave();/*TEST1-thedumbplayerB*/for(i=0;i<3;i++){/*assertplayerAclicksthebuttonsuccessfully*/如果(!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]);/*assertplayerBclicksthebutton成功*/if(!click_butt_functionals[!click_butt_functionals][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]);}}intmain(intargc,char**argv){pthread_tthread;gtk_init(&argc,&argv);/*startthetictactoeapplication*/window=gtk_window_new(GTK_WINDOW_TOPLEVEL);ttt=tictactoe_new();gtk_container_add(window,ttt);gtk_widget_show_all(window);/*starttheGtk+dispatcher*/pthread_create(&thread,NULL,ttt_functional_test_gtk_main,NULL);/*launchtestroutines*/ttt_functional_test_dumb_player_b();/*终止应用程序*/gdk_threads_enter();gtk_main_quit();gdk_threads_leave();return(0);}(题图:opensource.com)