Tutorial

This section aims to show by the example how to setup first funq tests on a project.

Requirements

This tutorial is based on a sample QT application that you can find here: https://github.com/parkouss/funq/tree/master/server/player_tester.

This sample application must be compiled to an executable binary file, player_tester.

To compile player_tester, just:

cd player_tester
qmake
make

This will create a player_tester executable file.

The two packages funq and funq-server must be installed. You can check that funq-server is installed by running:

funq -h

And that funq is installed with:

nosetests -h | grep 'with-funq'

Important

funq-server and the tested executable player_tester must be compiled with the same Qt version. You can check it with ldd for example.

If you just installed funq-server with pip (or did not specified any specific qmake path), then you are probably good.

Tests file tree

The file tree of a funq project is basically a folder that contains test files and a funq configuration file, funq.conf.

First, create a tutorial folder next to the player_tester binary file:

mkdir tutorial
cd tutorial

Now you have to write the configuration file funq.conf. Here is the most minimalistic configuration file:

[applitest]
executable = ../player_tester

Write your first test

You can now write your first test. Put the following content in a file called test_1.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
 --------- Module's documentation ---------
This file is part of the funq tutorial. It currently defines
one test method.
"""

from funq.testcase import FunqTestCase
import time

class MyTestCase(FunqTestCase):
    # identify the configuration
    __app_config_name__ = 'applitest'

    def test_my_first_test(self):
        """
         --------- Test method documentation ---------
        """
        # do nothing for 3 seconds
        time.sleep(3)

This file contains one test, that do nothing except wait for 3 seconds.

Note

The “applitest” configuration is described in the funq configuration file by the section of the same name.

Note

Subclass funq.testcase.FunqTestCase ensure that each test method will start the application and close it properly.

Test execution

Well done ! Let’s run this first test. Type the following command:

nosetests --with-funq

One window must appear, and close after a few seconds. The output on the terminal must look like this:

.
----------------------------------------------------------------------
Ran 1 test in 3.315s

OK

Note

The option --with-funq given to nosetests allow to use the funq plugin that will read the configuration file and execute your tests.

Note

nosetests has multiples options to allow for example the generation of an xml file to format tests result. See nosetests -h.

And voilà! You have written and launched your first funq test. Now let’s go a bit further by adding two tests and use an aliases file.

Let’s first create the aliases file.

Aliases file

This file associate a name (an alias) to graphical objects identified by their path. This behavior allow to keep running the written tests even if the widgets moves in the tested application or if the code of the tested application is refactored.

applitest.aliases file:

# the main central widget
mainWidget = fenPrincipale::widgetCentral

# and some other widgets

btnTest = {mainWidget}::btnTest

dialog1 = fenPrincipale::QMessageBox
dialog1_label = {dialog1}::qt_msgbox_label
tableview = {mainWidget}::tableView
treeview = {mainWidget}::treeView

Note

This file support variables substitution by using brackets, allowing to avoid useless and dangerous copy/paste.

Note

Some aliases are predefined. See Predifined graphical kit aliases.

Now you need to modify the funq.conf configuration file to indicate the use of this aliases file. Add the following line in the applitest section:

aliases = applitest.aliases

Do something with the widgets

Let’s write another tests in a new file, test_widgets.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
This file is part of the funq tutorial. It briefly shows widget
interaction.
"""

from funq.testcase import FunqTestCase
from funq.client import FunqError

class TestCase2(FunqTestCase):
    # identify the configuration
    __app_config_name__ = 'applitest'

    def test_libelle_btn_test(self):
        """
        Test the test button libelle
        """
        # use  the "btnTest" alias
        btn_test = self.funq.widget('btnTest')
        properties = btn_test.properties()
        
        self.assertEquals(properties['text'], 'Test')

    def test_open_dialog(self):
        """
        Test that a dialog is open when user click on the test button.
        """
        self.funq.widget('btnTest').click()
        dlg_label = self.funq.widget('dialog1_label')
        
        self.assertEquals(dlg_label.properties()['text'], "Button clicked")
    
    def test_tableview_content(self):
        """
        Test the data in tableview.
        """
        view = self.funq.widget('tableview')
        items = list(view.model_items().iter())
        self.assertEquals(len(items), 16)
        
        for item in items:
            text = "row {r}, column {c}".format(r=item.row,
                                                c=item.column)
            self.assertEquals(item.value, text)

    def test_some_treeview_content(self):
        """
        test some data in the treeview
        """
        model = self.funq.widget('treeview').model_items()
        
        item = model.item_by_named_path([u"item 1", u"item 1-2"])
        parent_item = model.item_by_named_path([u"item 1"])
        
        self.assertEquals(item.value, u"item 1-2")
        self.assertIn(item, parent_item.items)

You can see that the member variable self.funq is the entry point to manipulate the tested application. It is an instance of funq.client.FunqClient.

Now you can start tests again:

nosetests --with-funq

Note

This time, 5 tests are launched! It’s normal because you have written 5 tests divided up in 2 files.

To launch the tests of one file only, name it on the command line:

nosetests --with-funq test_widgets.py

Important

It is really important even for functional tests to not write tests that depends on others tests. In other words, the order of test execution must not be important. This allow to limit side effects and to find quickly why a test failed. This being said, nosetests does not assure any order in test execution.

Going further

This is the end of this tutorial. To go further, you must look at the API documentation!