Thursday 31 August 2017

TrafficControl: Test Driven Development

Test Driven Development (TDD) is a process for software development is based on automated tests to develop new functionality.

TDD is based on five steps:
  1. Define an automated test and add it to the test sequence. Ideally, that test case should make the target code fail.
  2. Run the test sequence and see that the target code fails on the new test. 
  3. Fix the target code so that the new test case is passing. At this stage, the fix should be "quick and dirty".
  4. Re-run the test sequence.
  5. Refactor the code. Here, the fix in step 3 should be refactored.
In TrafficControl, I'll show an example of unit testing. The tcStation object can add and remove waiting passengers. One kind of tcStation is a Junction, that shouldn't be able to add and remove passengers. So, one new test is to check whether a Junction can add passengers.

1. Add a test: station_junctionHasNoPassengersAfterAddingTen()

2. Run the test sequence. The target code failed the test as the junction added ten passengers,

3. Fix the target code. I need to both add a method tcStation::isJunction(), and also modify the method tcStation::changeNbrOfPassengers().
 4. Re-run the test sequence. Now, the program doesn't change the number of passengers if the station is a junction, as expected.
5. Refactor (Not needed in this particular case)

As with other tools, it is important to be pragmatic and understand when TDD is useful and when it should be avoided. Having a dogmatic view on different tools/methods/frameworks will lead to a lot of time spent on suboptimal solutions.

"You may have the best hammer but not all problems are nails." In some cases "happy testing" / happy coding is necessary. User interface development, for example may be difficult to use with TDD. The TDD process doesn't encourage long-term design considerations, which is crucial for bigger projects.

Saturday 26 August 2017

TrafficControl: The First Unit Tests - tcStation

The first unit tests for TrafficControl address one single station object. This will be a brain-storming session, where I add a lot of test cases without implementing them. In those cases, I have commented out the test cases that are yet to be implemented.

The commented test cases are not implemented yet. I also add a short description of the test cases.

When creating one station object, the default values must be verified:
  • Is the station empty initially, both with regard to the number of trains and passengers?
  • What happens if invalid coordinates are sent to the constructor of station? If the coordinates are float values, but too big (-100.0, 199)?
  • What happens if the station name is already taken?
When creating test cases, I sometimes realise that I need to extend the existing target code to be more testable and observable. That's the very purpose of verification: identifying ways to improve the code.

The test case "station_noCoordinatesAtCreation()" reveals that it useful to add a boolean "hasCoordinates" and a method "tcStation::hasCoordinates();".

The next blog post will introduce Test-Driven Development and show an example of using that methodology.

Monday 21 August 2017

TrafficControl: Integrating QtTest Into TrafficControl

After some hours looking at official Qt Documentation, internet forum posts and blogs, I found out how to add Qt Tests to the project, and it is quite easy!

A separate folder named test was created for the test code, where I added a C++ file with the name "tst_traffic.cpp".


The project file gets a debug clause (build commands that are only applied for debug builds):
When running QMake the next time for debug builds, the file main.cpp will be removed from sources. Instead the file tst_traffic.cpp will be added to the sources. Also, the testlib is loaded.

The test cases are listed as private slots and implemented as functions. The QVERIFY macro is used for the verdict.



The test report is shown below.

The next blog posts will cover the new test cases. The target code will be developed in parallel, since I need to change it to be more testable. I'll also use Test Driven Development, which I'll describe in the next blog post.

Wednesday 16 August 2017

TrafficControl: Some Resources on qTest/Google Test

Qt Applications are normally tested with Google Test plugin or Qt Test. I should learn to master handle both of them.

Qt Test:
There is some official documentation:
http://doc.qt.io/qtcreator/creator-autotest.html
http://doc.qt.io/qt-5/qtest-tutorial.html
http://doc.qt.io/qt-5/qtest-overview.html

Also, there are some blog posts:
http://imaginativethinking.ca/qtest-101-writing-unittests-qt-application/

An old but useful video from the 2010 dev days and also some Qt videos below:







Google Test
I need to learn Google Test and Google Mock Test

The documentation on the Git repo is very useful.

Christian Adam has provided a blog post covering background and a example of setting up a simple test.

Further, a slideshow from a webinar can be found here.

Friday 11 August 2017

TrafficControl: Protecting the Code

After reaching the milestone in the second last blog post, I've done some refactoring of the code to make it cleaner and simpler to maintain:
  • Reviewing parameter names
  • Adding Doxygen comments
  • Replacing STL vectors with QLists
  • Calling the QML JavaScript functions directly
The next step will be to introduce automated tests. This is crucial to protect trafficControl from new and existing bugs.

Initially, I'll learn how to use the test framework in Qt Test. After that, I'll focus on some areas:
  • How to reset the traffic network between different tests
  • Module testing - to verify the modules/functions
  • Input files - how to detect problems in the network definition files
  • Useability/User Interfaces
  • Test-Driven Development - Mainly for different traffic scenarios
  • Performance Testing/Optimization 
  • Memory leak tests

Sunday 6 August 2017

TrafficControl: Possible Areas for Optimization

When designing software, it is often important to compromise between simplicity and performance. Optimizing source code can improve performance, but it will also make the software more complex and harder to debug and maintain in the future.

For TrafficControl, I've identified some areas where I can optimize it, if that will be needed later on:
  • Accessing QML items from C++: In the QML slot, the JavaScript is iterating over the QML object tree until it finds the item with the corresponding objectName. It should be possible to save the index for the particular QML item when creating it, and save the index so that C++ objects can access the QML item directly. 
  • Updating position of trains on tracks: Currently, the program is iterating through all coordinates to find wich two consecutive coordinates to interpolate between for every update. It should be possible to rmake the program remember the last coordinate and search from there.
  • Implementing model/view for the QML map: Explore whether this will improve the performance.
Before doing all that, I'll review, refactor and clean up the code.

Tuesday 1 August 2017

TrafficControl: Mapping Position on Track to Coordinates

TrafficControl is supposed to present the train positions on the tracks in real-time. To achieve this, the trains needs to get their locations, when providing their location on the tracks.

I'll implement a function in tcTrack that will work in three steps:
  1. In the track constructor, the coordinates are already provided. A Haversine formula will calculate the accumulated distances between the first waypoint of the track and all following waypoints.
    1. Import coordinates to constructor - DONE
    2. Implement Haversine function - DONE
    3. Use Haversine function to generate list of accumulated distances - DONE
  2. A function will take an integer as input parameter (position on track in meters). The function will return the last waypoint that is before the input position. - DONE
  3. Another function that interpolates to provide the accurate coordinate.


The result can be seen in the video below. The color of the tracks are: Green (empty), Yellow (occupied). The color of the border of the station circles are: Green (empty), Yellow (populated) and Red (full).



After upgrading Qt from 5.7 to 5.9.1, that came two weeks ago, the map issue with tiles is resolved.
The road map forQt 5.9 canbe found on the web site.