[Effective WX] wx的UI UnitTest explained

在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被采用。

你可能感兴趣的:([Effective WX] wx的UI UnitTest explained)