<a href="http://s3.51cto.com/wyfs02/M01/08/4F/wKiom1nfPTLyee8UAAD0CZRlZGA708.png-wh_651x-s_1657377668.png" target="_blank"></a>
這個簡單教程教你如何測試你應用的功能。
自動化測試用來保證你程式的品質以及讓它以預想的運作。單元測試隻是檢測你算法的某一部分,而并不注重各元件間的适應性。這就是為什麼會有功能測試,它有時也稱為內建測試。
功能測試簡單地與你的使用者界面進行互動,無論它是網站還是桌面應用。為了展示功能測試如何工作,我們以測試一個 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);
}
ttt_functional_test_util_reaction_time_long()
usleep(TTT_FUNCTIONAL_TEST_UTIL_REACTION_TIME_LONG);
直到獲得控制狀态,逾時函數才會推遲執行。這對于一個異步執行的動作很有幫助,這也是為什麼采用這麼長的時延。
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();
與圖形化使用者界面互動
為了模拟使用者互動的操作, 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 */
gdk_test_simulate_button(window,
x,
y,
1,
GDK_BUTTON1_MASK,
GDK_BUTTON_PRESS);
GDK_BUTTON_RELEASE);
ttt_functional_test_util_reaction_time_long();
return(TRUE);
我們想要保證按鈕處于激活狀态,是以我們提供一個空閑條件函數:
ttt_functional_test_util_idle_test_toggle_active(
GtkToggleButton **toggle_button)
gboolean do_idle;
do_idle = TRUE;
if(*toggle_button != NULL &&
GTK_IS_TOGGLE_BUTTON(*toggle_button) &&
gtk_toggle_button_get_active(*toggle_button)){
do_idle = FALSE;
return(do_idle);
測試場景
因為這個 Tictactoe 程式非常簡單,我們隻需要確定點選了一個 GtkToggleButton 按鈕即可。一旦該按鈕肯定進入了激活狀态,功能測試就可以執行。為了點選按鈕,我們使用上面提到的很友善的 util 函數。
如圖所示,我們假設,填滿第一行,玩家 A 就赢,因為玩家 B 沒有注意,隻填充了第二行。
GtkWindow *window;
Tictactoe *ttt;
void*
ttt_functional_test_gtk_main(void *)
gtk_main();
pthread_exit(NULL);
ttt_functional_test_dumb_player_b()
GtkButton *buttons[3][3];
guint i;
/* to avoid race-conditions copy the buttons */
memcpy(buttons, ttt->buttons, 9 * sizeof(GtkButton *));
/* 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])){
&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 */
gtk_main_quit();
return(0);
(題圖:opensource.com)
本文作者:Joël Krähemann
來源:51CTO