本文共 12070 字,大约阅读时间需要 40 分钟。
gtk+程序
需要进行自动测试以确保程序的质量并按预期工作。 单元测试仅检查算法的某些部分,而不关注每个组件如何组合在一起。 这就是功能测试(有时称为集成测试)的来源。
功能测试基本上是通过网站还是桌面应用程序与您的用户界面进行交互。 为了向您展示它的工作原理,让我们看一下如何测试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 , & current_time ) ; if ( start_time. tv_sec + timeout -> tv_sec < current_time. tv_sec ) { break ; } } ttt_functional_test_util_reaction_time ( ) ; }
为了模拟用户交互, 提供了我们需要的功能。 要在这里进行工作,我们仅需要以下三个功能:
例如,要测试按钮单击,我们执行以下操作:
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程序非常简单,因此我们只需要确保单击了 。 一旦断言按钮进入活动状态,功能测试就可以继续进行。 要单击按钮,我们使用上面提供的方便的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 ( ) ; ( 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 ] ) ) { ( - 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 ] ) ) { ( - 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 ) ; }
翻译自:
gtk+程序
转载地址:http://pgszd.baihongyu.com/