aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@qt.io>2023-01-25 16:01:27 +0100
committerEike Ziller <eike.ziller@qt.io>2023-02-28 15:42:48 +0000
commitcace5a57f2a372e5879e12ff0b5d5781f513969b (patch)
treecb25407542cef685ee7216cc456f1494aa8dd55d
parent5e866bbf2ff18b006bca05dbc165e2e418cc0ab9 (diff)
Plugins: Add documentation about testing
Add information about how to write plugin tests and how to integrate unit tests. Change-Id: I13721f03c4c55a265a93f71a7c4d892f3e53a6bb Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
-rw-r--r--doc/qtcreatordev/examples/exampleplugin/CMakeLists.txt29
-rw-r--r--doc/qtcreatordev/examples/exampleplugin/example.cpp43
-rw-r--r--doc/qtcreatordev/examples/exampleplugin/example.h2
-rw-r--r--doc/qtcreatordev/examples/exampleplugin/example_global.h2
-rw-r--r--doc/qtcreatordev/examples/exampleplugin/examplefunctions.h9
-rw-r--r--doc/qtcreatordev/examples/exampleplugin/tst_mytest.cpp21
-rw-r--r--doc/qtcreatordev/src/creating-plugins.qdoc6
-rw-r--r--doc/qtcreatordev/src/plugin-tests.qdoc103
8 files changed, 213 insertions, 2 deletions
diff --git a/doc/qtcreatordev/examples/exampleplugin/CMakeLists.txt b/doc/qtcreatordev/examples/exampleplugin/CMakeLists.txt
index 69df3ec4da..65fba00089 100644
--- a/doc/qtcreatordev/examples/exampleplugin/CMakeLists.txt
+++ b/doc/qtcreatordev/examples/exampleplugin/CMakeLists.txt
@@ -20,6 +20,24 @@ find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
set(QtX Qt${QT_VERSION_MAJOR})
#! [3]
+#! [5]
+# Add a CMake option that enables building your plugin with tests.
+# You don't want your released plugin binaries to contain tests,
+# so make that default to 'NO'.
+# Enable tests by passing -DWITH_TESTS=ON to CMake.
+option(WITH_TESTS "Builds with tests" NO)
+
+if(WITH_TESTS)
+ # Look for QtTest
+ find_package(${QtX} REQUIRED COMPONENTS Test)
+ # Tell CMake functions like add_qtc_plugin about the QtTest component.
+ set(IMPLICIT_DEPENDS Qt::Test)
+
+ # Enable ctest for auto tests.
+ enable_testing()
+endif()
+#! [5]
+
#! [4]
add_qtc_plugin(Example
PLUGIN_DEPENDS
@@ -36,5 +54,16 @@ add_qtc_plugin(Example
example.h
example_global.h
exampleconstants.h
+ examplefunctions.h
)
#! [4]
+
+#! [6]
+# conditionally add auto tests
+if(WITH_TESTS)
+ add_qtc_test(tst_mytest
+ SOURCES tst_mytest.cpp
+ DEPENDS Example
+ )
+endif()
+#! [6]
diff --git a/doc/qtcreatordev/examples/exampleplugin/example.cpp b/doc/qtcreatordev/examples/exampleplugin/example.cpp
index f001fad511..3dd54659f0 100644
--- a/doc/qtcreatordev/examples/exampleplugin/example.cpp
+++ b/doc/qtcreatordev/examples/exampleplugin/example.cpp
@@ -1,5 +1,7 @@
#include "example.h"
+
#include "exampleconstants.h"
+#include "examplefunctions.h"
#include <coreplugin/icore.h>
#include <coreplugin/icontext.h>
@@ -13,9 +15,31 @@
#include <QMainWindow>
#include <QMenu>
+//! [test include]
+#ifdef WITH_TESTS
+#include <QtTest>
+#endif
+//! [test include]
+
namespace Example {
namespace Internal {
+//! [plugin tests]
+#ifdef WITH_TESTS
+class MyPluginTests : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testMyTest()
+ {
+ // a failing test
+ QVERIFY(false);
+ }
+};
+#endif
+//! [plugin tests]
+
ExamplePlugin::ExamplePlugin()
{
// Create your members
@@ -53,6 +77,11 @@ bool ExamplePlugin::initialize(const QStringList &arguments, QString *errorStrin
Core::ActionManager::actionContainer(Core::Constants::M_TOOLS)->addMenu(menu);
//! [add menu]
+//! [register tests]
+#ifdef WITH_TESTS
+ addTest<MyPluginTests>();
+#endif
+ //! [register tests]
return true;
}
@@ -81,4 +110,18 @@ void ExamplePlugin::triggerAction()
//! [slot implementation]
} // namespace Internal
+
+//! [exported function]
+int addOne(int i)
+{
+ return i; // that is wrong!
+}
+//! [exported function]
+
} // namespace Example
+
+//! [include moc]
+#ifdef WITH_TESTS
+#include "example.moc"
+#endif
+//! [include moc]
diff --git a/doc/qtcreatordev/examples/exampleplugin/example.h b/doc/qtcreatordev/examples/exampleplugin/example.h
index e858e92180..dfde7849a1 100644
--- a/doc/qtcreatordev/examples/exampleplugin/example.h
+++ b/doc/qtcreatordev/examples/exampleplugin/example.h
@@ -1,7 +1,5 @@
#pragma once
-#include "example_global.h"
-
#include <extensionsystem/iplugin.h>
//! [namespaces]
diff --git a/doc/qtcreatordev/examples/exampleplugin/example_global.h b/doc/qtcreatordev/examples/exampleplugin/example_global.h
index 0ea029c5c7..f051e16dd9 100644
--- a/doc/qtcreatordev/examples/exampleplugin/example_global.h
+++ b/doc/qtcreatordev/examples/exampleplugin/example_global.h
@@ -3,6 +3,8 @@
#pragma once
+#include <qglobal.h>
+
#if defined(EXAMPLE_LIBRARY)
# define EXAMPLE_EXPORT Q_DECL_EXPORT
#else
diff --git a/doc/qtcreatordev/examples/exampleplugin/examplefunctions.h b/doc/qtcreatordev/examples/exampleplugin/examplefunctions.h
new file mode 100644
index 0000000000..7a618cbe57
--- /dev/null
+++ b/doc/qtcreatordev/examples/exampleplugin/examplefunctions.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "example_global.h"
+
+namespace Example {
+
+int EXAMPLE_EXPORT addOne(int i);
+
+} // namespace Example
diff --git a/doc/qtcreatordev/examples/exampleplugin/tst_mytest.cpp b/doc/qtcreatordev/examples/exampleplugin/tst_mytest.cpp
new file mode 100644
index 0000000000..12cf7b1e31
--- /dev/null
+++ b/doc/qtcreatordev/examples/exampleplugin/tst_mytest.cpp
@@ -0,0 +1,21 @@
+#include "examplefunctions.h"
+
+#include <QtTest>
+
+class tst_MyTest : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void mytest();
+};
+
+void tst_MyTest::mytest()
+{
+ // a failing test
+ QCOMPARE(Example::addOne(1), 2);
+}
+
+QTEST_GUILESS_MAIN(tst_MyTest)
+
+#include "tst_mytest.moc"
diff --git a/doc/qtcreatordev/src/creating-plugins.qdoc b/doc/qtcreatordev/src/creating-plugins.qdoc
index ef9ce82959..6a83c6d9bf 100644
--- a/doc/qtcreatordev/src/creating-plugins.qdoc
+++ b/doc/qtcreatordev/src/creating-plugins.qdoc
@@ -38,6 +38,12 @@
\li \l{Distributing Plugins}
\endlist
+ \section1 Topics
+
+ \list
+ \li \l{Adding Tests}
+ \endlist
+
\section1 Design Principles
\list
diff --git a/doc/qtcreatordev/src/plugin-tests.qdoc b/doc/qtcreatordev/src/plugin-tests.qdoc
new file mode 100644
index 0000000000..78d9c6c4b6
--- /dev/null
+++ b/doc/qtcreatordev/src/plugin-tests.qdoc
@@ -0,0 +1,103 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page plugin-tests.html
+ \title Adding Tests
+
+ There are two main ways of testing your plugin code:
+
+ \list
+ \li \l{Plugin Tests}
+ \li \l{Auto Tests}
+ \endlist
+
+ Both have their specific use cases and setup, which is described in the
+ following sections.
+
+ \section1 Setting up CMake
+
+ Before adding tests, prepare your build files. They need to look for the
+ QtTest dependency and have a CMake option for building your plugin with
+ tests:
+
+ \snippet exampleplugin/CMakeLists.txt 5
+
+ \section1 Plugin Tests
+
+ Plugin tests are deeply integrated into your plugin and its
+ interaction with \QC. To add a test for something that requires
+ the infrastructure of \QC or your plugin to be set up, write a plugin
+ test.
+
+ Plugin tests are executed by starting \QC with the \c{-test <pluginname>}
+ command line argument. \QC then fully loads your plugin and all the plugins
+ that it depends on, going through the normal \l{Plugin Life Cycle}. After
+ your plugin and all dependencies are fully initialized, your tests are
+ executed. Afterwards, \QC automatically closes. Therefore, your plugin
+ tests have access to all exported functionality of all \QC plugins that
+ your plugin depends on, like \c{Core::ICore}. Use QtTest's normal test
+ macros, like \c{QVERIFY} or \c{QCOMPARE} to report your test's success or
+ failure.
+
+ To add plugin tests, add a QObject based class with private slots for your
+ tests, and register it with \l{ExtensionSystem::IPlugin::addTest()} in your
+ plugin's \l{ExtensionSystem::IPlugin::initialized()} method. Guard all test
+ related code with a check for \c{WITH_TESTS}, to avoid shipping a binary
+ release of your plugin with test functions.
+
+ Include QtTest:
+
+ \snippet exampleplugin/example.cpp test include
+
+ Then implement the test functions:
+
+ \snippet exampleplugin/example.cpp plugin tests
+
+ Register your test in ExtensionSystem::IPlugin::initialize():
+
+ \snippet exampleplugin/example.cpp register tests
+
+ If you declared the test object in the source file, like in this example,
+ also include the \c{.moc} file that is required for Qt's meta object
+ compiler:
+
+ \snippet exampleplugin/example.cpp include moc
+
+ \section1 Auto Tests
+
+ To add a test that does not depend on a running \QC infrastructure, use an
+ auto test that lives independent of your plugin interface. Parsers are a
+ common example, but you can test many things in this way if they have been
+ written in a modular way.
+
+ Even though your test does not live in your plugin interface,
+ like with plugin tests, you can still link the test to libraries and also
+ your plugin library itself, to avoid code duplication or duplicate
+ compilation of code.
+
+ In principle you can use any auto test framework,
+ but QtTest is a simple one that integrates well with Qt, and is also used
+ for the \l{plugin tests}{Plugin Tests}.
+
+ To add your test, add the test's C++ file, and use \c{add_qtc_test} in your
+ CMake file to add the test target. If your test uses your plugin library,
+ add it as a dependency with \c{DEPENDS}.
+
+ In the following example, the plugin exports a function \c{addOne}:
+
+ \quotefile exampleplugin/examplefunctions.h
+
+ And implements it in a source file:
+
+ \snippet exampleplugin/example.cpp exported function
+
+ The test is linked against the plugin library target with \c{DEPENDS}:
+
+ \snippet exampleplugin/CMakeLists.txt 6
+
+ The QtTest based test then includes the header from the plugin and
+ tests the function:
+
+ \quotefile exampleplugin/tst_mytest.cpp
+*/