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>
This commit is contained in:
Eike Ziller
2023-01-25 16:01:27 +01:00
parent 5e866bbf2f
commit cace5a57f2
8 changed files with 213 additions and 2 deletions

View File

@@ -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]

View File

@@ -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]

View File

@@ -1,7 +1,5 @@
#pragma once
#include "example_global.h"
#include <extensionsystem/iplugin.h>
//! [namespaces]

View File

@@ -3,6 +3,8 @@
#pragma once
#include <qglobal.h>
#if defined(EXAMPLE_LIBRARY)
# define EXAMPLE_EXPORT Q_DECL_EXPORT
#else

View File

@@ -0,0 +1,9 @@
#pragma once
#include "example_global.h"
namespace Example {
int EXAMPLE_EXPORT addOne(int i);
} // namespace Example

View File

@@ -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"

View File

@@ -38,6 +38,12 @@
\li \l{Distributing Plugins}
\endlist
\section1 Topics
\list
\li \l{Adding Tests}
\endlist
\section1 Design Principles
\list

View File

@@ -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
*/