Skip to main content

Mehrfachtestbaustein implementieren

Um viele zusammengehörige Testfälle in nur einem Testbaustein zu realisieren, können Sie das Pragma {attribute 'test' := 'multitest'} verwenden: Sie dekorieren einen Testbaustein mit ETrigA-Verhalten mit diesem Pragma. Bei der Protokollierung während des Testablaufs werden dann zusätzliche Informationen übermittelt. So wird beispielsweise das Testergebnis für jeden einzelnen Testfall übermittelt und protokolliert. Dafür werden weitere Ein- und Ausgänge benötigt.

Grundgerüst für den Testfall erstellen

Ein Testfall ist ein Funktionsbaustein, der einem bestimmten Schema folgt (Schnittstellenkonvention). Um das Einhalten des Schemas zu erleichtern, empfehlen wir, den Wizard zu nutzen. Wenn Sie einen Testfall manuell erstellen, sollte er immer von TM.BaseMultiTest ableiten. (Obsolete Testbaustein-Implementierungen).

Prozedur. Objekt Unittest einfügen
  1. Fügen Sie den Testfall-Funktionsbaustein unter einer Applikation oder im POU-Pool hinzu. Wählen Sie dazu den Befehl Objekt hinzufügenUnittest aus den Kontextmenü.

    Der Dialog Unittest hinzufügen öffnet sich.

  2. Geben Sie folgende Parameter ein:

    Name der POU: TestCase_1

    Typ: Extend TM.BaseMultiTest

    _cds_icon_checked.png Optionale Methoden hinzufügen

    _cds_icon_checked.png Implementierungsvorlagen hinzufügen

    _cds_icon_checked.png Erklärende Kommentare hinzufügen

    Testfallkategorie: BasicTests

  3. Bestätigen Sie den Dialog mit Hinzufügen und speichern Sie das Projekt.

    Ein neuer Funktionsbaustein mit den Methoden Execute, Setup, Teardown und Abort entsteht.

Für weitere Informationen siehe: Unittest hinzufügen

Testlogik implementieren

  1. Deklarieren Sie eine Instanz des Prüflings im Deklarationsteil des Testbaustein. Das Beispiel testet einen CTU-Standardbaustein.

    {attribute 'test':='multitest'}
    {attribute 'testcasetimeout':='15000'}
    FUNCTION_BLOCK CTU_TestCases EXTENDS TM.BaseMultiTest
    VAR_INPUT
    END_VAR
    VAR_OUTPUT
    END_VAR
    VAR
    	counter : CTU;	// testee instance
    	cycleCounter : INT; // independant test control variable
    END_VAR
  2. Initialisieren Sie den Prüfling im Implementierungsteil der Methode prvStart. Das Beispiel initialisiert den CTU per Reset und initialisiert gegebenenfalls Variablen, die für den Testablauf benötigt werden. Die prvStart-Methode wird einmalig vor prvCyclicAction aufgerufen.

    SUPER^.prvStart();  // mandatory - don't change
    
    // Initialize the testee
    counter(CU:=FALSE, RESET:=TRUE);	// reset the counter; note: initialization per test case must be performed in prvCyclicAction
    
    // Initialize test control variable for first test case
    cycleCounter := 0;
  3. Rufen Sie den Prüfling auf und prüfen Sie dessen Ergebnisses in der Methode prvCyclicAction. Die Methode prvCyclicAction wird solange aufgerufen, bis xDone auf TRUE gesetzt wurde. Der Prüfling kann somit je Testfall über mehrere SPS-Zyklen aufgerufen werden. Das folgende Beispiel implementiert nur einen Testfall (CASE 0), weitere Testfälle können jedoch nach diesem Schema einfach hinzugefügt werden.

    SUPER^.prvCyclicAction();   // mandatory - dont' change
     
    CASE diTestCaseIndex OF
        0:	// test case #0; add test cases as new CASEs
            IF xGetTestInfo THEN    // initializate test case
                //  define mandatory test case information
                wsTestCaseName := "Count from 0 to 5";
                wsTestCaseCategories := "CTU";
                diTestCaseTimeout := 500;
                 
                xDone := TRUE;  // signal test case initialization done
            ELSE
    			IF (cycleCounter = 0) THEN
    				// prepare test case
    				counter(CU:=FALSE, RESET:=TRUE, PV:=5);	
    	
    			// stimulate testee as long as we expect: 5 rising edges to count to 5 equals minimum 10 cycles
    			ELSIF (cycleCounter < 10) THEN 
    				// check: counter limit not reached yet
    				TM.Assert_Bool_IsFalse(THIS^, counter.Q, "Counter signaled limit reached prematurely");
    				TM.Assert_Word_Less(THIS^, 5, counter.CV, "Counter reached limit unexpectedly");	
    			
    				counter(CU:= (NOT counter.CU), RESET:=FALSE);	// Trigger counter with rising edges
    				
    				xDone := FALSE;   // signal test still running
    			ELSE
    				// check: counter reached limit
    				TM.Assert_Bool_IsTrue(THIS^, counter.Q, "Counter did not signal limit reached");
    				TM.Assert_Word_Equal(THIS^, 5, counter.CV, "Counter did not reach limit");
    				 
    				xDone := TRUE;    // mandatory: signal test completed
    			END_IF
    			
    			IF xDone OR xError THEN
    				cycleCounter := 0;	// clean up for next test case
    			ELSE
    				cycleCounter := cycleCounter + 1;	// count cycles	
    			END_IF
            END_IF
        ELSE
            IF diTestCaseIndex < 0 THEN  // mandatory, signal number of test cases, if called with (diTestCaseIndex < 0)
                diTestCaseCount := 1;
                xDone := TRUE;
            ELSE    // mandatory, don't remove: fail for invalid test case index
                wsInfo := "Invalid test case index";
                iError := 2;
            END_IF
    END_CASE
  4. Eine Deinitialisierung des Tests könnte in der Methode prvResetOutputs stattfinden, wird aber in diesem Beispiel nicht benötigt. Löschen Sie die Methode.

  5. Es muss kein besonderer Code ausgeführt werden, wenn der Test in einen Timeout läuft. Löschen Sie die Methode prvAbort.

Testelement IEC-Unittest konfigurieren

  1. Geben Sie im Titel einen Testfallnamen ein.

    Beispiel: N_001_Test

    Bei Testausführung erscheint der Titel als Testfallname.

  2. Geben Sie in Timeout Gerät lesen (ms) eine Zeit an. Beispiel: 5000

    Hinweis: Bei jedem Testfall wird mindestens beim Auslesen von Teststatus und Testergebnis gewartet. Außerdem wird beim Einloggen gewartet, wenn der Applikationsstatus ausgelesen wird.

    Beim Auslesen von Variablen wird gewartet, bis der Timout abgelaufen ist, erst dann wird gelesen.

  3. Geben Sie in Erneute Login-Versuche an, wie oft maximal versucht wird den Onlinebetrieb herzustellen. Beispiel: 3

  4. Klicken Sie links oben in der Tabelle Ausgewählte Kategorien.

    Ein Eingabefeld erscheint.

  5. Geben Sie alle Kategorien ein, die in diesem Testfall aufgerufen werden.

    Beispiel: BasicTests

    Alle Test-Funktionsbausteine, die mit dem Attribut 'testcategory' := 'BasicTests' dekoriert sind, werden in diesem Testfall aufgerufen.

Testskript ausführen

Voraussetzung: Die Testumgebung ist vorbereitet. Das Testprojekt ist im CODESYS Development System geöffnet und die Geräte- und Kommunikationseinstellungen sind konfiguriert. Diese notwendigen Anweisungen werden durch einen vorbereitenden Testfall im Testskript vorgenommen.

  1. Der Inhalt des Ordners Generated Unit Tests wird gelöscht, um die generierten Bausteine eines vorherigen IEC-Unittests zu entfernen.

  2. Das Projekt und die Bibliotheken zum Testen werden nach Testtabellen durchsucht. Dann werden die Funktionsbausteine für die Ausführung der Testtabellen im Ordner Generated Unit Tests generiert.

  3. Das Projekt und die Bibliotheken, die unter Bibliotheken zum Testen aufgelistet sind, werden durchsucht nach Funktionsbausteinen und Programmen, die als Test markiert sind.

    Dann werden unter den ermittelten Programmen und Funktionsbausteinen diejenigen entfernt, die über die Testkategorien oder den Namen ausgeschlossen sind.

    Die verbleibenden Programme und Funktionsbausteine werden für den Test berücksichtigt.

  4. Ein Backup der ursprünglichen Applikation wird erstellt.

  5. Die Testfälle werden als IEC-Code in PLC_PRG eingefügt. Die (in der Deklaration und in der Implementierung) hinzugefügten Codezeilen werden mit Generated by IEC Unit Test markiert.

  6. Wenn die Applikation zu groß für die Steuerung ist, werden automatisch die Tests auf mehrere Applikationen aufgeteilt. Eine oder mehrere ablauffähige Applikationen werden generiert.

  7. Der Test mit der erzeugten Applikation / den erzeugten Applikationen wird ausgeführt.

    Folgenden Einzelschritte werden abgearbeitet:

    • Eine Testapplikation wird auf die Steuerung geladen.

    • Die Testapplikation wird gestartet.

    • Die Testfälle werden ausgeführt. Wenn in den Testfunktionsbausteinen die Stringvariable sInfo oder wsInfo verwendet wird, erscheint deren Inhalt im Testreport.

    • Der Timeout wird überwacht.

    • Das Testergebnis wird überprüft und danach Testreport übermittelt.

    • Applikation wird von der Steuerung entfernt.

  8. Ein Testreport, der alle Testergebnisse enthält, wird generiert.

Tipp

Beachten Sie das Testrepository Default-Test-Repository. Dort finden Sie das Testskript Examples.IecUnitTest. In diesem Testskript können Sie einen IEC-Unittest nachvollziehen, also die vorbereitenden Maßnahmen Projekt laden, Gerät aktualisieren und Kommunikationseinstellungen setzen. Dann folgt ein IEC-Unittest. Die Testfälle, die durchlaufen werden, kommen aus dem Projekt Example_IecUnitTest.project. Sie finden das Projekt im Verzeichnis C:\ProgramData\CODESYS Test Manager.

Die Beispielskripte sind für eine Steuerung CODESYS Control Win (32 Bit) erstellt. Falls Sie eine andere Steuerung einsetzen, müssen Sie die Parameter der Skript-Aktion UpdateDevice anpassen.