aboutsummaryrefslogtreecommitdiffstats
path: root/src/imports
diff options
context:
space:
mode:
authorMitch Curtis <mitch.curtis@qt.io>2016-11-17 15:18:17 +0100
committerMitch Curtis <mitch.curtis@qt.io>2016-12-14 07:20:30 +0000
commit7aaebe557476c088d339f1b4b114a671885c4ea8 (patch)
tree827ca5f0b3e94b705d9a1a62597181eb28ff1893 /src/imports
parent9fbc5aa8866bbc19cc0db9f5f247276f36f3e283 (diff)
TestCase: add createTemporaryObject(), createTemporaryQmlObject()
A typical pattern with QML tests is to dynamically create an item and then destroy it at the end of the test function: TestCase { id: testCase name: "MyTest" when: windowShown function test_click() { var item = Qt.createQmlObject("import QtQuick 2.0; Item {}", testCase); verify(item); // Test item... item.destroy(); } } The problem with this pattern is that any failures in the test function will cause the call to item.destroy() to be skipped, leaving the item hanging around in the scene until the test case has finished. This can result in interference with future tests; for example, by blocking input events or producing unrelated debug output that makes it difficult to follow the code's execution. By calling e.g. createTemporaryQmlObject() instead, the object is guaranteed to be destroyed at the end of the test function: TestCase { id: testCase name: "MyTest" when: windowShown function test_click() { var item = createTemporaryObject("import QtQuick 2.0; Item {}", testCase); verify(item); // Test item... // Don't need to worry about destroying "item" here. } } [ChangeLog][TestCase] Added createTemporaryObject() and createTemporaryQmlObject() functions that can be used to ensure that dynamically created objects are destroyed at the end of each test function. Change-Id: I483342052462aa86464c86bf2082892712dceb58 Task-number: QTBUG-56361 Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io> Reviewed-by: Michael Brasser <michael.brasser@live.com>
Diffstat (limited to 'src/imports')
-rw-r--r--src/imports/testlib/TestCase.qml160
-rw-r--r--src/imports/testlib/qmldir1
2 files changed, 161 insertions, 0 deletions
diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml
index a874fd4fe2..ad7533c550 100644
--- a/src/imports/testlib/TestCase.qml
+++ b/src/imports/testlib/TestCase.qml
@@ -206,6 +206,59 @@ import Qt.test.qtestroot 1.0
will fail. Use the \l when and windowShown properties to track
when the main window has been shown.
+ \section1 Managing Dynamically Created Test Objects
+
+ A typical pattern with QML tests is to
+ \l {Dynamic QML Object Creation from JavaScript}{dynamically create}
+ an item and then destroy it at the end of the test function:
+
+ \code
+ TestCase {
+ id: testCase
+ name: "MyTest"
+ when: windowShown
+
+ function test_click() {
+ var item = Qt.createQmlObject("import QtQuick 2.0; Item {}", testCase);
+ verify(item);
+
+ // Test item...
+
+ item.destroy();
+ }
+ }
+ \endcode
+
+ The problem with this pattern is that any failures in the test function
+ will cause the call to \c item.destroy() to be skipped, leaving the item
+ hanging around in the scene until the test case has finished. This can
+ result in interference with future tests; for example, by blocking input
+ events or producing unrelated debug output that makes it difficult to
+ follow the code's execution.
+
+ By calling \l createTemporaryQmlObject() instead, the object is guaranteed
+ to be destroyed at the end of the test function:
+
+ \code
+ TestCase {
+ id: testCase
+ name: "MyTest"
+ when: windowShown
+
+ function test_click() {
+ var item = createTemporaryQmlObject("import QtQuick 2.0; Item {}", testCase);
+ verify(item);
+
+ // Test item...
+
+ // Don't need to worry about destroying "item" here.
+ }
+ }
+ \endcode
+
+ For objects that are created via the \l {Component::}{createObject()} function
+ of \l Component, the \l createTemporaryObject() function can be used.
+
\sa {QtTest::SignalSpy}{SignalSpy}, {Qt Quick Test Reference Documentation}
*/
@@ -358,6 +411,8 @@ Item {
/*! \internal */
property var qtest_events: qtest_events_normal
TestEvent { id: qtest_events_normal }
+ /*! \internal */
+ property var qtest_temporaryObjects: []
/*!
\qmlmethod TestCase::fail(message = "")
@@ -461,6 +516,110 @@ Item {
throw new Error("QtQuickTest::fail")
}
+ /*!
+ \since 5.9
+ \qmlmethod object TestCase::createTemporaryQmlObject(string qml, object parent, string filePath)
+
+ This function dynamically creates a QML object from the given \a qml
+ string with the specified \a parent. The returned object will be
+ destroyed (if it was not already) after \l cleanup() has finished
+ executing, meaning that objects created with this function are
+ guaranteed to be destroyed after each test, regardless of whether or
+ not the tests fail.
+
+ If there was an error while creating the object, \c null will be
+ returned.
+
+ If \a filePath is specified, it will be used for error reporting for
+ the created object.
+
+ This function calls
+ \l {QtQml::Qt::createQmlObject()}{Qt.createQmlObject()} internally.
+
+ \sa {Managing Dynamically Created Test Objects}
+ */
+ function createTemporaryQmlObject(qml, parent, filePath) {
+ if (typeof qml !== "string") {
+ qtest_results.fail("First argument must be a string of QML; actual type is " + typeof qml,
+ util.callerFile(), util.callerLine());
+ throw new Error("QtQuickTest::fail");
+ }
+
+ if (!parent || typeof parent !== "object") {
+ qtest_results.fail("Second argument must be a valid parent object; actual type is " + typeof parent,
+ util.callerFile(), util.callerLine());
+ throw new Error("QtQuickTest::fail");
+ }
+
+ if (filePath !== undefined && typeof filePath !== "string") {
+ qtest_results.fail("Third argument must be a file path string; actual type is " + typeof filePath,
+ util.callerFile(), util.callerLine());
+ throw new Error("QtQuickTest::fail");
+ }
+
+ var object = Qt.createQmlObject(qml, parent, filePath);
+ qtest_temporaryObjects.push(object);
+ return object;
+ }
+
+ /*!
+ \since 5.9
+ \qmlmethod object TestCase::createTemporaryObject(Component component, object parent, object properties)
+
+ This function dynamically creates a QML object from the given
+ \a component with the specified \a parent and \a properties.
+ The returned object will be destroyed (if it was not already) after
+ \l cleanup() has finished executing, meaning that objects created with
+ this function are guaranteed to be destroyed after each test,
+ regardless of whether or not the tests fail.
+
+ If there was an error while creating the object, \c null will be
+ returned.
+
+ This function calls
+ \l {QtQml::Component::createObject()}{component.createObject()}
+ internally.
+
+ \sa {Managing Dynamically Created Test Objects}
+ */
+ function createTemporaryObject(component, parent, properties) {
+ if (typeof component !== "object") {
+ qtest_results.fail("First argument must be a Component; actual type is " + typeof component,
+ util.callerFile(), util.callerLine());
+ throw new Error("QtQuickTest::fail");
+ }
+
+ if (!parent && parent !== null) {
+ qtest_results.fail("Second argument must be a parent object or null; actual type is " + typeof parent,
+ util.callerFile(), util.callerLine());
+ throw new Error("QtQuickTest::fail");
+ }
+
+ if (properties && typeof properties !== "object") {
+ qtest_results.fail("Third argument must be an object; actual type is " + typeof properties,
+ util.callerFile(), util.callerLine());
+ throw new Error("QtQuickTest::fail");
+ }
+
+ var object = component.createObject(parent, properties ? properties : ({}));
+ qtest_temporaryObjects.push(object);
+ return object;
+ }
+
+ /*!
+ \internal
+
+ Destroys all temporary objects that still exist.
+ */
+ function qtest_destroyTemporaryObjects() {
+ for (var i = 0; i < qtest_temporaryObjects.length; ++i) {
+ var temporaryObject = qtest_temporaryObjects[i];
+ if (temporaryObject)
+ temporaryObject.destroy();
+ }
+ qtest_temporaryObjects = [];
+ }
+
/*! \internal */
// Determine what is o.
// Discussions and reference: http://philrathe.com/articles/equiv
@@ -1492,6 +1651,7 @@ Item {
qtest_runInternal(prop, arg)
qtest_results.finishTestData()
qtest_runInternal("cleanup")
+ qtest_destroyTemporaryObjects()
qtest_results.finishTestDataCleanup()
// wait(0) will call processEvents() so objects marked for deletion
// in the test function will be deleted.
diff --git a/src/imports/testlib/qmldir b/src/imports/testlib/qmldir
index 9da8ebb4be..e5757f6a88 100644
--- a/src/imports/testlib/qmldir
+++ b/src/imports/testlib/qmldir
@@ -3,4 +3,5 @@ plugin qmltestplugin
classname QTestQmlModule
typeinfo plugins.qmltypes
TestCase 1.0 TestCase.qml
+TestCase 1.2 TestCase.qml
SignalSpy 1.0 SignalSpy.qml