summaryrefslogtreecommitdiffstats
path: root/old/doc/src/qtuitest_plugins.qdoc
diff options
context:
space:
mode:
Diffstat (limited to 'old/doc/src/qtuitest_plugins.qdoc')
-rw-r--r--old/doc/src/qtuitest_plugins.qdoc297
1 files changed, 297 insertions, 0 deletions
diff --git a/old/doc/src/qtuitest_plugins.qdoc b/old/doc/src/qtuitest_plugins.qdoc
new file mode 100644
index 0000000..d3161d3
--- /dev/null
+++ b/old/doc/src/qtuitest_plugins.qdoc
@@ -0,0 +1,297 @@
+/*!
+
+\page qtuitest_plugins.html
+\title Creating a QtUiTest Test Widget
+
+\tableofcontents
+
+\section1 Introduction
+
+QtUiTest provides support for simulating high-level user interface interactions.
+Conceptually these take the form of, for example, \i{Select 'Dog' from the widget labelled 'Animal'}, or \i{Enter 'Bob' into the widget labelled 'Name'}.
+
+Crucially, testcases do not need to specify the exact type of each widget or how to interact with it.
+Instead the logic for interacting with different types of widgets resides on the system under test, either alongside the implementation of each widget or in a plugin.
+Each class of widget which QtUiTest can interact with has a corresponding wrapper class, referred to as a test widget.
+
+This document explains when a test widget must be created and how it is implemented.
+
+\section1 When a Test Widget is Required
+
+QtUiTest includes support for most Qt widgets. When a new type of widget is introduced, a test widget may be required.
+
+In these cases, a test widget will almost certainly have to be implemented:
+\list
+\o A custom widget implements painting and interaction by overriding functions such as \l{QWidget::}{paintEvent()} and \l{QWidget::}{keyPressEvent()}.
+\o The behavior of a major user interface element has been customized (for example, a device profile is used which has a device-specific way of accepting incoming phone calls).
+\endlist
+
+In these cases, a test widget will usually not be required:
+\list
+\o A custom widget acts primarily as a container for standard widgets.
+ In this case, QtUiTest can interact with the contained widgets as normal.
+\o A custom widget subclasses a standard widget and correctly reimplements virtual functions.
+ For example, a subclass of QAbstractItemView which performs custom painting with a custom model will work with no additional effort if \l{QAbstractItemView::}{visualRect()} is implemented correctly (for mouse interaction), standard item view key event handling is used and the item model accurately reports its data.
+\endlist
+
+As an example, consider a testcase for creating a contact in the addressbook application.
+At one point in the testcase, we wish to set the contact's title to Doctor:
+
+\c{select("Dr", "Title");}
+
+This requires that the widget referred to by "Title" implements the \l{QtUiTest::}{SelectWidget} interface.
+If this is not the case, the testcase fails with a failure message like the following:
+
+\c{FAIL! : sys_addressbook::creating_a_contact() ERROR: Title (QComboBox(0x80b2768)) is not a SelectWidget.}
+
+This error message indicates that the "Title" widget, which is a QComboBox, does not have any corresponding test widget which implements the \l{QtUiTest::}{SelectWidget} interface, and therefore can't have items selected from it.
+
+Note that not all errors arising from missing test widgets will be of this form.
+
+\section1 Choosing the Right Interfaces
+
+Test widgets must implement one or more of a standard set of interfaces belonging to the \l{QtUiTest} namespace.
+
+Test widget interfaces map to the conceptual purpose of a widget from a user's perspective.
+The available interfaces are listed below:
+
+\table
+\header \o Interface \o Applies to \o Examples
+\row
+\o \l{QtUiTest::}{Widget}
+\o All 2D user interface elements.
+\o QWidget
+\row
+\o \l{QtUiTest::}{ActivateWidget}
+\o Widgets which are activated to trigger some action.
+\o QAbstractButton
+\row
+\o \l{QtUiTest::}{CheckWidget}
+\o Widgets which can be checked and unchecked.
+\o QCheckBox, QRadioButton
+\row
+\o \l{QtUiTest::}{TextWidget}
+\o Widgets which display text.
+\o QLineEdit, QTextEdit, QMenu, QAbstractItemView, QLabel, many others
+\row
+\o \l{QtUiTest::}{InputWidget}
+\o Widgets which can accept text input.
+\o QLineEdit, QTextEdit
+\row
+\o \l{QtUiTest::}{ListWidget}
+\o Widgets which display a list of items.
+\o QAbstractItemView, QMenu
+\row
+\o \l{QtUiTest::}{SelectWidget}
+\o Widgets which allow an item to be selected from a list.
+\o QAbstractItemView, QMenu
+\endtable
+
+Each test widget should implement all interfaces applicable to the wrapped widget.
+Test widgets can subclass other test widgets and reuse already-implemented interfaces.
+For example, the test widget for QCheckBox could inherit from the test widget for QAbstractButton to avoid having to reimplementing the \l{QtUiTest::}{Widget}, \l{QtUiTest::}{TextWidget} and \l{QtUiTest::}{ActivateWidget} interfaces again.
+
+Some test widget interfaces are strongly related and are likely to be implemented in pairs.
+Almost all widgets which accept text input also display the entered text, so any test widget which implements \l{QtUiTest::}{InputWidget} will usually implement \l{QtUiTest::}{TextWidget}.
+Almost all widgets which can be selected from also display the selectable items, so any test widget which implements \l{QtUiTest::}{SelectWidget} will usually implement \l{QtUiTest::}{ListWidget}.
+
+\section1 Implementing the Test Widget
+
+To make a new test widget visible to QtUiTest, there are two separate approaches which can be taken, each with their own advantages.
+
+\section2 Plugin method
+
+The plugin method involves adding the test widget code into a plugin which is then loaded by QtUiTest at runtime.
+This is the most suitable method to use in most cases and the only method used for the test widgets shipped with QtUiTest.
+
+Advantages to the plugin method compared to the multiple inheritance method include:
+\list
+\o The code for the test widget is cleanly separated from the wrapped widget and hence easy to omit from a release build without the need for \c{#ifdef}s or similar measures.
+\o It is easier to reuse test widget code because test widgets aren't directly tied to wrapped widgets.
+\o It is possible to customize the process of \l{QtUiTest::WidgetFactory::find()}{finding} and \l{QtUiTest::WidgetFactory::create()}{creating} test widgets.
+\o Typical multiple inheritance difficulties are avoided, such as the test widget interface API shadowing the API of the wrapped widget.
+\endlist
+
+\section3 Test widget class
+
+Each test widget class needs to inherit from QObject and the relevant test widget interfaces.
+
+In practice, it is common for a test widget class hierarchy to be written which closely mirrors the wrapped widget class hierarchy.
+This makes it possible to avoid rewriting the code for common interfaces such as \l{QtUiTest::Widget} many times.
+
+It is possible to subclass the test widgets shipped with QtUiTest, although they are not guaranteed to remain source or binary compatible across releases.
+The convention used in the reference plugins to generate a test widget class name is to take the wrapped widget class name, drop any leading Q, and prefix Test.
+For example, the test widget wrappers for QWidget and QAbstractItemView are named TestWidget and TestAbstractItemView respectively.
+
+Using the plugin approach, while subclassing from TestWidget to avoid reimplementing the \l{QtUiTest::Widget} interface, would result in a class declaration like the following:
+
+\code
+#include <testwidget.h>
+class TestCustomComboBox : public TestWidget, public QtUiTest::ListWidget,
+ public QtUiTest::SelectWidget, public QtUiTest::TextWidget
+{
+Q_OBJECT
+Q_INTERFACES(
+ QtUiTest::ListWidget
+ QtUiTest::SelectWidget
+ QtUiTest::TextWidget)
+
+public:
+ TestCustomComboBox(CustomComboBox* wrapped);
+ virtual ~TestCustomComboBox();
+
+ // QtUiTest::ListWidget members
+ virtual QStringList list() const;
+ virtual QRect visualRect(const QString&) const;
+
+ // QtUiTest::SelectWidget members
+ virtual bool canSelect(QString const&) const;
+ virtual bool select(QString const&);
+
+ // QtUiTest::TextWidget members
+ virtual QString text() const;
+ virtual QString selectedText() const;
+
+private:
+ CustomComboBox* m_wrapped;
+};
+\endcode
+
+Implementing the test widget is as simple as retrieving the necessary information from the wrapped widget.
+Test widgets can create and use other test widgets at runtime when necessary, as shown in the \c{list()} function below.
+
+\code
+TestCustomComboBox::TestCustomComboBox(CustomComboBox* wrapped)
+ : m_wrapped(wrapped)
+{}
+
+QStringList TestCustomComboBox::list() const
+{ return qtuitest_cast<QtUiTest::ListWidget*>(m_wrapped->view())->list(); }
+
+QString TestCustomComboBox::text() const
+{ return list().join("\n"); }
+
+QString TestCustomComboBox::selectedText() const
+{ return m_wrapped->currentText(); }
+\endcode
+
+Memory management is handled automatically; there will be a maximum of one TestCustomComboBox instance created for any CustomComboBox and it will be destroyed when the underlying CustomComboBox is destroyed.
+
+\section3 Test widget factory
+
+When using the plugin approach it is also necessary to implement a factory class.
+This serves as the entry point to the plugin and handles the logic for creating test widgets.
+
+The test widget factory must subclass \l{QtUiTest::WidgetFactory} and implement the \l{QtUiTest::WidgetFactory::}{create()} function to create test widgets and the \l{QtUiTest::WidgetFactory::}{keys()} function to report which widget classes can be wrapped.
+
+\code
+class TestWidgetsFactory : public QObject, public QtUiTest::WidgetFactory
+{
+ Q_OBJECT
+ Q_INTERFACES(QtUiTest::WidgetFactory)
+
+public:
+ TestWidgetsFactory();
+
+ virtual QObject* create(QObject*);
+ virtual QStringList keys() const;
+};
+\endcode
+
+The \l{QtUiTest::WidgetFactory::}{create()} function is called when a new test widget is to be created.
+Our example widget factory handles CustomComboBox widgets and nothing else.
+
+\code
+QObject* TestWidgetsFactory::create(QObject* wrapped)
+{
+ if ((CustomComboBox* ccb = qobject_cast<CustomComboBox*>(wrapped))) {
+ return new TestCustomComboBox(ccb);
+ }
+ return 0;
+}
+\endcode
+
+The \l{QtUiTest::WidgetFactory::}{keys()} function must report which classes can be handled by this factory.
+Any object passed into the \l{QtUiTest::WidgetFactory::}{create()} function is guaranteed to be one of the classes returned by \l{QtUiTest::WidgetFactory::}{keys()}.
+Classes are handled from most to least specific; when creating a test widget for CustomComboBox, a factory which handles CustomComboBox has higher priority over a factory which handles QWidget.
+If two or more factories handle the same class, it is undefined which factory will be asked to create the test widget.
+
+Our example factory can only handle CustomComboBox widgets so it returns that class name only.
+\code
+QStringList TestWidgetsFactory::keys() const
+{
+ return QStringList() << "CustomComboBox";
+}
+\endcode
+
+Finally, the plugin needs to be exported using the standard Qt plugin mechanism:
+\code
+#include <qplugin.h>
+Q_EXPORT_PLUGIN2(customtestwidgets, TestWidgetsFactory)
+\endcode
+
+In the project's \c{qbuild.pro}, the \c{PLUGIN_TYPE} must be set to \c{qtuitest_widgets}.
+
+\section2 Multiple inheritance method
+
+The multiple inheritance approach requires the widget being wrapped to implement the test widget interfaces itself.
+
+Advantages to the multiple inheritance method compared to the plugin method include:
+\list
+\o The code for the test widget is in the same file as the wrapped widget and hence is more likely to be maintained if the widget is modified.
+\o The test widget has access to the internal structures of the wrapped widget.
+\o There is no need to write a \l{QtUiTest::}{WidgetFactory} class to handle creation of test widgets.
+\endlist
+
+For example, implementing a custom combobox class along with all of the associated test widget interfaces would result in a class declaration like:
+
+\code
+class CustomComboBox : public QComboBox, public QtUiTest::Widget,
+ public QtUiTest::ListWidget, public QtUiTest::SelectWidget,
+ public QtUiTest::TextWidget
+{
+Q_OBJECT
+Q_INTERFACES(
+ QtUiTest::Widget
+ QtUiTest::ListWidget
+ QtUiTest::SelectWidget
+ QtUiTest::TextWidget)
+
+public:
+ CustomComboBox(QWidget* parent = 0);
+ ...
+
+ // CustomComboBox members
+ void addCustomItem(const QVariant& item);
+ void addCustomItems(const QVariantList& items);
+ ...
+
+ // QtUiTest::Widget members
+ virtual const QRect& geometry() const;
+ virtual QRect rect() const;
+ ...
+
+ // QtUiTest::ListWidget members
+ virtual QStringList list() const;
+ virtual QRect visualRect(const QString&) const;
+ ...
+
+ // etc...
+};
+\endcode
+
+Implementing the test widget is as simple as returning the necessary information.
+Test widgets can create and use other test widgets at runtime when necessary, as shown in the \c{list()} function below.
+
+\code
+QStringList CustomComboBox::list() const
+{ return qtuitest_cast<QtUiTest::ListWidget*>(view())->list(); }
+
+QString CustomComboBox::text() const
+{ return list().join("\n"); }
+
+QString CustomComboBox::selectedText() const
+{ return currentText(); }
+\endcode
+
+*/