Unit Tests with Team Developer: TDUnit

Motivation

Like many developers who are working with the Team Developer from Unify (Gupta / Centura), our company has the task to raise the existing TD application to the version 5.x or 6.x of the development environment. Central issue for us is „unicode“, because we had written quite a few external C libraries which perform string processing. They had been written 10 years ago because of performance issues. So we face the choice to make the C libraries either unicode-compatible or refactor them within the team developer. We have decided for the second option. Problem: How can we ensure, that over 100 newly written functions do the same as their predecessors?

Unit tests

A look outside the box shows that other programming languages (Java, .NET) use quality assurance techniques. There, at least in large projects, it is customary to write so-called unit tests in addition to the actual program code. During my investigations, mainly two sources were very helpful to me: The book The Art of Unit Testing: With Examples in .Net by Roy Osherove, as well as the unit testing framework NUnit for Visual Studio.

Definition of Unit Tests

A very condensed and personal definition of the unit test method:

What is unit testing?

  • Unit Tests are one of several components of the software quality assurance.
  • Unit Tests check individual, isolated functions of the production code.
  • Unit Tests can run at any time. Now and in the distant future.
  • Unit tests can be run automatically.
  • Unit tests are fast.
What is a unit test framework?
  • It helps programmers as much as possible in the writing and running of unit test functions.
Why should you write unit tests?
  • To ensure that a particular function does what it should do now.
  • To ensure that a particular function is still doing what it should do  in future.
  • In order to save time in the maintenance of complex software.

Unit testing framework

In general you can write unit tests without a supporting framework – nearly every TD developer has done that already in some cases. But the acceptance to cover all productive functions with unit tests without a supporting framework tends zero in a developer team. So we need a unit testing framework for the Team Developer. Unfortunately, despite intensive research, I could not find a single unit testing framework for the TD. I had to create one myself.
The aim was to support our development team as well as possible in writing unit tests. The well matured project „NUnit“ for visual studio was the blueprint.
In detail, the following requirements are met with TDUnit:
  • The developer needs to create only the test function.
  • He must not even call the test function somewhere. TDUnit recognizes test functions on its own.
  • A set of ready-made assert functions simplifys the writing of understandable tests. One-liners are possible in many cases.
  • Logging is done automatically.
  • If one adheres simple, meaningful naming conventions, one may omit in most cases a self-written logging-message.
  • Debugging of the testing- and productioncode in single step mode is easily possible.
First practice tests show a good acceptance in the development team.

TDUnit

These are the steps you have to perform in order to use TDUnit

  • First you need an .apt-,. app-or .apl file containing production code. The file must compile. Let’s call it Sample.app. In my example, the function under test is an internal function. (Currently TDUnit covers internal functions, functional classes and external functions. Functions within form windows and dialogs are currently still not testable (easily)).
  • Next, an empty SampleTest.app file should be created. Two libraries have to be included: the testing framework TDUnit.apl and the production file under test, in this case Sample.app.
  • Then, you must create a functional class in the test file. Three conventions have to be adhered: 1) The class must be derived from _UnitTestBase. 2) The name of that class must end with „Tests“ – e.g. InternalFunctionsTests. 3) The member function GetContext() must be overwritten with exacty this one line of code: Return SalContextCurrent()
  • The actual tests are written as member functions within the just created class. Each test function must contain an AssertXXX function. Convention applying to the naming of the test function: „Name of the function you want to test“ _ „Description of the test of“_“expected behavior“ – e.g. Calculator_EmptyString_Zero.
  • Running the test from the menu debug/go or press F7. The Testrunner window will appear and all existing tests are performed automatically. If the assert function confirmed the expected behavior it will appear in green color otherwise red.
The result looks like this:

Downloads

TDUnit is written with the Team Developer 3.1. The zip file contains the framework (TDUnit.apl), as well as a SampleApp with tests. Also a more detailed PDF documentation (in german).
I’d like to read your feedback.
Advertisements

Unit Tests mit dem Team Developer: TDUnit

Motivation

Wie wahrscheinliche viele Entwickler, die mit dem Team Developer von Unify (Gupta / Centura) arbeiten, stehen wir in unserer Firma vor der Aufgabe, die bestehende TD-Applikation auf die Version 5.x bzw. 6.x der Entwicklungsumgebung anzuheben. Zentrales Thema für uns ist „Unicode“ und zwar deshalb, weil wir aus (historischen) Performance-Gründen etliche externe C-Bibliotheken geschrieben hatten, die u.a. String-Verarbeitung durchführen. Wir stehen also vor der Wahl, die C-Bibliotheken Unicode-fähig zu machen oder sie im Team-Developer nachzuprogrammieren. Wir haben uns für die zweite Option entschieden. Problem dabei: Wie stellt man sicher, dass die über 100 neu zu schreibenden Funktionen dasselbe tun, wie ihre Vorgänger?

Unit Tests

Ein Blick über den Tellerrand zeigt, dass man in anderen Programmiersprachen (Java, .NET) beim Thema Qualistätssicherung längst weiter ist. Dort ist es – zumindest in größeren Projekten – üblich, zusätzlich zum eigentlichen Programmcode sogenannte Unit Tests zu schreiben. Bei meinen Recherchen waren für mich v.a. zwei Quellen sehr hilfreich: Das Buch The Art of Unit Testing: Deutsche Ausgabe (mitp Professional) von Roy Osherove, sowie das dort beschriebene Unit Testframework NUnit für Visual Studio.

Eine zugegeben sehr verkürzte und persönliche Darstellung der Unit Test Methode:

Was sind Unit Tests?

  • Unit Test ist eine von mehreren Komponenten der Software-Qualitätssicherung.
  • Unit Tests testen einzelne Funktionen des Produktionscodes möglichst isoliert.
  • Unit Tests können jederzeit und auch in ferner Zukunft aufgerufen werden.
  • Unit Tests können automatisiert aufgerufen und ausgewertet werden.
  • Unit Tests sind schnell.

Was ist ein Unit Test Framework?

  • Es unterstützt den Entwickler so gut wie irgend möglich beim Schreiben und Ausführen von Unit Testfunktionen.

Warum sollte man Unit Tests schreiben?

  • Um jetzt sicherzustellen, dass eine bestimmte Funktion tut was sie soll.
  • Um in Zukunft sicherzustellen, dass eine bestimmte Funktion immer noch tut was sie soll.
  • Damit man bei der Pflege von komplexer Software Zeit spart.

Unit Testframework

Nun kann man Unit Tests im Prinzip auch ohne ein unterstützendes Framework schreiben – und im einen oder andere Fall hat das sicher jeder TD-Entwickler auch schon mal gemacht. Die Akzeptanz für einen „flächendeckenden“ Einsatz dieser Methode dürfte im Entwickler-Team jedoch gegen Null tendieren. Es muss also ein Unit Testframework für den Team Developer her. Leider konnte ich trotz intensiver Recherche kein einziges Unit Testframework für den TD finden. Ich musste also selbst eines erstellen.

Das Ziel war, unser Entwicklerteam so gut wie möglich beim Schreiben von Unit Tests zu unterstützen. Des weiteren habe ich mich, so gut es ging, am bewährten NUnit orientiert. Heraus kam TDUnit, ein Unit Testframework für den Team Developer.

Im Detail werden mit TDUnit folgende Anforderungen erfüllt:

  • Der Entwickler muss lediglich die Testfunktion erstellen.
  • Er muss die Testfunktion NICHT selbst aufrufen. TDUnit erkennt Testfunktionen eigenständig.
  • Ein Set von vorgefertigten Assert-Funktionen hilft, einfache und verständliche Tests zu schreiben. Einzeiler sind in vielen Fällen möglich.
  • Die Protokollierung erfolgt automatisch.
  • Hält man sich an sinnvolle Benennungskonventionen, kann in den allermeisten Fällen auf eine selbstgeschriebene Nachricht für die Protokollierung verzichtet werden.
  • Debugging des Test- und Produktivcodes im Einzelschrittmodus ist ohne weiteres möglich

Erste Praxistests zeigen eine gute Akzeptanz im Entwicklerteam.

TDUnit

Zunächst benötigt man eine .apt-, .app- oder .apl-Datei mit Produktiv-Code. Die Datei muss komplierbar sein. Nennen wir sie Sample.app. Die zu testende Funktion ist im Beispielt eine Internal Function. (Im derzeitigen Testframework können Internal Functions, Functional Classes und External Functions getestet werden. Funktionen innerhalb von Dialogen und Form-Windows sind derzeit noch nicht (ohne weiteres) testbar).

Als nächstes sollte eine leere SampleTest.app-Datei erstellt werden. Zwei Librarys sind einzubinden: Das Testframework TDUnit.apl und die zu testende Produktiv-Datei, in unserem Fall Sample.app.

In der Test-Datei muss dann eine Functional Class erstellt werden. Drei Konventionen sind dabei einzuahlten: 1) Sie muss von _UnitTestBase abgeleteitet werden. 2) Der Name der Klasse muss auf „Tests“ enden also z.B. InternalFunctionsTests. 3) Die Funktion GetContext() muss überschrieben werden. Inhalt muss genau eine Codezeile sein: Return SalContextCurrent()

Die eigentlichen Tests werden als Funktionen innerhalb der gerade erstellten Klasse geschrieben. Jede Testfunktion muss eine AssertXXX-Funktion enthalten. Für die Benennung der Testfunktion gilt die Konvention: „Name der zu testenden Funktion“_“Beschreibung des Tests“_“Erwartetes Verhalten“. In der SampleApp z.B. so: Function: Calculator_EmptyString_Zero.

Ausgeführt wird der Test über das Menü Debug/Go oder mit F7. Es erscheint das Testrunner-Window und alle vorhandenen Tests werden automatisch ausgeführt. Ist eine Testfunktion in Ordnung – dh. die Assert-Funktion bestätigt das erwartete Verhalten – wird sie im Testrunner grün angezeigt anderenfalls rot.

Das Ergebnis sieht dann so aus:

Downloads

TDUnit ist mit dem Team Developer 3.1 geschrieben. Die Zip-Datei enthält das Framework (TDUnit.apl), sowie eine SampleApp mit Tests. Ebenso eine ausführlichere PDF-Doku.

TDUnit.zip
TDUnit Dokumentation

Über Feedback würde ich mich freuen.