在wx2.9.4中,wx支持了UI UnitTest。我们来看下这个framework是如何实现的UI UnitTest
1. wxUIActionSimulator类
wxUIActionSimulator类利用不同平台的API(windows:win32api, linux: X11)实现了基本事件发送机制。
1). 鼠标相关事件, 2). 键盘按键相关事件
bool MouseMove ( long x , long y);
bool MouseMove ( const wxPoint & point ) { return MouseMove ( point. x , point . y); }
bool MouseDown ( int button = wxMOUSE_BTN_LEFT );
bool MouseUp ( int button = wxMOUSE_BTN_LEFT );
// Higher level interface, use it if possible instead
bool MouseClick ( int button = wxMOUSE_BTN_LEFT );
bool MouseDblClick ( int button = wxMOUSE_BTN_LEFT );
bool MouseDragDrop ( long x1 , long y1, long x2 , long y2 ,
int button = wxMOUSE_BTN_LEFT );
// Keyboard simulation
// -------------------
// Low level methods for generating key presses and releases
bool KeyDown ( int keycode , int modifiers = wxMOD_NONE )
{ return Key ( keycode, modifiers , true ); }
bool KeyUp ( int keycode , int modifiers = wxMOD_NONE )
{ return Key ( keycode, modifiers , false ); }
// Higher level methods for generating both the key press and release for a
// single key or for all characters in the ASCII string "text" which can currently
// contain letters, digits and characters for the definition of numbers [+-., ].
bool Char ( int keycode , int modifiers = wxMOD_NONE );
bool Text ( const char *text );
在windows平台上,实现文件是src/msw/uiaction.cpp
在gtk平台,是利用x11提供的接口: src/unix/uiactionx11.cpp
另外common/uiactioncmn.cpp文件实现了一些基本公共函数.
2. 关于event loop
一个APP有一个main event loop,同时任何一个ShowModal所产生的window都会有一个active event loop。
在unit test app中,这个app并没有创建自己的main event loop,因为main event loop是在OnRun调用被创建的,但是这个test app并没有借用默认的OnRun,而是自己实现了OnRun,从而运行CPPUnit的run函数.
3. 两者结合实现UI的unit test
测试代码通过自己发送自定义事件,然后自己接收,来实现定制流程的event-driven ui test:
那么test app如何做到事件转发和处理的呢?以下代码段完成了这种机制:
wxUIActionSimulator sim;
// Add some extra distance to take account of window decorations
sim .MouseMove ( m_button-> GetScreenPosition () + wxPoint (10, 10));
sim .MouseClick ( wxMOUSE_BTN_LEFT );
// Process the resulting button event
wxYield ();
bool wxYield()
{
return wxTheApp && wxTheApp-> Yield ();
}
bool wxAppConsoleBase ::Yield ( bool onlyIfNeeded )
{
wxEventLoopBase * const loop = wxEventLoopBase :: GetActive();
if ( loop )
return loop -> Yield( onlyIfNeeded );
wxScopedPtr <wxEventLoopBase > tmpLoop ( CreateMainLoop ());
return tmpLoop -> Yield( onlyIfNeeded );
}
wxEventLoopBase::Yield函数将会调用Pending/Dispatch函数,来获取事件然后进行处理。
所以这种事件触发和接收方式,完全是客户端代码主动意愿的。什么时候发送事件和处理事件,全部由测试程序代码决定。
每一个event loop在调用它的Run函数开头,都会将设置自己为Actived EventLoop,代表自己是当前的event loop,这种用法在ShowModal被采用。