.NET C# Java Javascript Exception

Unit tests are an essential tool for every programmer to ensure functioning of his software. Software bugs cost time and money, so you need an automated solution to find these bugs and preferably before the software is used. Unit tests should be used wherever software is professionally developed. This article is intended to provide a […]

Unit tests are an essential tool for every programmer to ensure functioning of his software. Software bugs cost time and money, so you need an automated solution to find these bugs and preferably before the software is used. Unit tests should be used wherever software is professionally developed. This article is intended to provide a quick introduction and allow an understanding of the benefits of unit tests.


Separate test programs are often written to test function blocks. In such a test program, an instance of the desired function block is created and called. The output variables are observed and manually checked for correctness. If these do not match the expected values, the function block is adjusted until it works as intended.

But testing software once is not enough. Amendments and extensions of a program are often responsible that functions or function blocks, that were previously tested and worked without errors, suddenly do not work correctly any longer. It is also possible that the correction of program errors can also affect other parts of the program and can lead to malfunctions in other parts of the code. Previously executed and completed tests must therefore be repeated manually.

One possible way to improve this is to automate the tests. For this purpose, a test program is developed which calls up the functionality of the program to be tested and checks the return values. A test program written once offers a number of advantages:

– The tests are automated and can therefore be repeated at any time with the same framework conditions (timings, …).

– Once written tests are retained for other team members.

Unit Tests

A unit test checks a very small and self-sufficient part (unit) of a software. In IEC 61131-3, this is a single function block or a function. Each test calls the unit to be tested (function block, method or function) with test data (parameters) and checks its reaction to this test data. If the delivered result matches the expected result, the test is considered passed. A test generally consists of a whole series of test cases that not only check one target/actual pair, but several of them.

A developer decides himself which test scenarios he implements. However, it makes sense to test with values that typically occur in practice when they are called. Consideration of limit values (extremely large or small values) or special values (zero pointer, empty string) is also useful. If all these test scenarios deliver correct values as expected, developer can assume that his implementation is correct.

A positive side-effect is that it gives developers less headaches to make complex changes to their code. After all, they can check the system at any time after making such changes. If no errors occur after such a change, it is most likely to have been successful.

However, the risk of poor test implementation must not be ignored. If these are inadequate or even false, but produce a positive result, this deceptive certainty will sooner or later lead to major problems.

The Unit Test Framework TcUnit

Unit test frameworks offer necessary functionalities to create unit tests quickly and effectively. They offer further advantages:

– Everyone in the team can extend the tests quickly and easily.

– Everyone is able to start the tests and check the results of the tests for correctness.

The unit test framework TcUnit was developed as part of a project. In fact, it is a PLC library that provides methods for verifying variables (assert methods). If a check was not successful, a status message is displayed in the output window. The assert methods are contained in the function block FB_Assert.

There is a method for each data type, whereby the structure is always similar. There is always a parameter that contains the actual value and a parameter for the setpoint. If both match, the method returns TRUE, otherwise FALSE. The parameter sMessage specifies the output text to be displayed in the event of an error. This allows you to assign the messages to the individual test cases. The names of the assert methods always begin with AreEqual.

Here, for example, the method checks a variable of type integer for validity.

Some methods contain additional parameters.

All standard data types (BOOL, BYTE, INT, WORD, STRING, TIME, …) have corresponding assert methods. Some special data types, such as AreEqualMEM for checking a memory area or AreEqualGIUD, are also supported.

The first Example

Unit tests are used to check individual function blocks independently of other components. These function blocks can be located in a PLC library or in a PLC project.

For the first example, the FB to be tested should be located in a PLC project. This is the function block FB_Foo.

Defines the time that the output bOut remains set if no further positive edges are applied to bSwitch.

bSwitchA positive edge sets the output bOut to TRUE. This remains active for the time tDuration. If the output is already set, the time tDuration is restarted.
bOffThe output bOut is immediately reset by a positive edge.
tDurationDefines the time that the output bOut remains set if no further positive edges are applied to bSwitch.

Unit tests are intended to prove that the FB_Foo function block behaves as expected. The code for testing is implemented directly in the TwinCAT project.

Project Setup

To separate the test code from the application, the folder TcUnit_Tests is created. The POU P_Unit_Tests is stored in this folder from which the respective test cases are called.

A corresponding test FB is created for each FB. This has the same name plus the postfix _Tests. In our example, the name is FB_Foo_Tests.

In P_Unit_Tests, an instance of FB_Foo_Tests is created and called.

PROGRAM P_Unit_Tests
 fbFoo_Tests : FB_Foo_Tests;


FB_Foo_Tests contains the entire test code for checking FB_Foo. In FB_Foo_Tests, an instance of FB_Foo is created for each test case. These are called with different parameters and the return values are validated using the assert methods.

The execution of the individual test cases takes place in a state machine, which is also managed by the PLC library TcUnit. This means, for example, that the test is automatically terminated as soon as an error has been detected.

Definition of Test Cases

The individual test cases must first be defined. Each test case occupies a certain area in the state machine.

For the naming of the individual test cases, several naming rules have proven useful, which help to make the test setup more transparent.

The name of the test cases that are to check an inbox of FB_Foo is composed of [input name]_[test condition]_[expected behaviour]. Test cases that test methods of FB_Foo are named similarly, i. e. [method name]_[test condition]_[expected behaviour].

The following test cases are defined according to this scheme:


Tests whether the output bOut is set to 1 s by a positive edge at bSwitch, if tDuration is set to t#1s.


Tests whether a positive edge at bSwitch causes the output bOut to become FALSE again after 1100 ms, if tDuration has been set to t#1s.


Tests whether the time tDuration is restarted by a new positive edge at bSwitch.


Tests whether the output bOut is set to FALSE by a positive edge at bOff.

Test Case Implementation

Each test case occupies at least one step in the state machine. In this example, the increment between the individual test cases is 16#0100. The first test case starts at 16#0100, the second at 16#0200, etc. In step 16#0000, initializations will be performed, whereas step 16#FFFF must be available, since this is started by the state machine as soon as an assert method has detected an error. If the test runs without errors, a message is displayed in 16#FF00 and the unit test for FB_Foo is finished.

The pragma region is very helpful to simplify navigation in the source code.

 bError : BOOL;
 bDone : BOOL;
 Assert : FB_ASSERT('FB_Foo');
 fbFoo_0100 : FB_Foo;
 fbFoo_0200 : FB_Foo;
 fbFoo_0300 : FB_Foo;
 fbFoo_0400 : FB_Foo;

CASE Assert.State OF
{region 'start'}
 bError := FALSE;
 bDone := FALSE;
 Assert.State := 16#0100;

{region 'Switch_RisingEdgeAndDuration1s_OutIsTrueFor1s'}
 Assert.State := 16#0200;

{region 'Switch_RisingEdgeAndDuration1s_OutIsFalseAfter1100ms'}
 Assert.State := 16#0300;

{region 'Switch_RetriggerSwitch_OutKeepsTrue'}
 Assert.State := 16#0400;

{region 'Off_RisingEdgeAndOutIsTrue_OutIsFalse'}
 Assert.State := 16#FF00;

{region 'done'}
 Assert.State := 16#FF10;

 bDone := TRUE;

{region 'error'}
 bError := TRUE;


There is a separate instance of FB_Foo for each test case. This ensures that each test case works with a newly initialized instance of FB_Foo. This avoids mutual influence of the test cases.

 fbFoo_0100(bSwitch := TRUE, tDuration := T#1S);
 Assert.AreEqualBOOL(TRUE, fbFoo_0100.bOut, 'Switch_RisingEdgeAndDuration1s_OutIsTrueFor1s');
 tonDelay(IN := TRUE, PT := T#900MS);
 IF (tonDelay.Q) THEN
 tonDelay(IN := FALSE);
 Assert.State := 16#0200;

The block to be tested is called for 900 ms. During this time, bOut must be TRUE, because bSwitch has been set to TRUE and tDuration is 1 s. The assert method AreEqualBOOL checks the output bOut. If it does not have the expected status, an error message is output. After 900 ms, you switch to the next test case by setting the property State of FB_Assert.

A test case can also consist of several steps:

 fbFoo_0300(bSwitch := TRUE, tDuration := T#500MS);
 Assert.AreEqualBOOL(TRUE, fbFoo_0300.bOut, 'Switch_RetriggerSwitch_OutKeepsTrue');
 tonDelay(IN := TRUE, PT := T#400MS);
 IF (tonDelay.Q) THEN
 tonDelay(IN := FALSE);
 fbFoo_0300(bSwitch := FALSE);
 Assert.State := 16#0310;

 fbFoo_0300(bSwitch := TRUE, tDuration := T#500MS);
 Assert.AreEqualBOOL(TRUE, fbFoo_0300.bOut, 'Switch_RetriggerSwitch_OutKeepsTrue');
 tonDelay(IN := TRUE, PT := T#400MS);
 IF (tonDelay.Q) THEN
 tonDelay(IN := FALSE);
 Assert.State := 16#0400;

Triggering of bSwitch is performed in line 7 and line 12. Lines 3 and 13 check whether the output remains set.

Output of Messages

After executing all test cases for FB_Foo, a message is output (step 16#FF00).

If an assert method detects an error, it is also displayed as a message.

If the AbortAfterFail property of FB_Assert is set to TRUE, the step 16#FFFF is called in case of an error and the test is terminated.

The assert method prevents the same message from being issued more than once in a single step. Multiple output of the same message, e. g. in a loop, is thus suppressed. By setting the MultipleLog property to TRUE, this filter is deactivated and every message is output.

Due to the structure shown above, the unit tests are clearly separated from the actual application. FB_Foo remains completely unchanged.

This TwinCAT solution is stored in the source code management (such as TFS or Git) together with the TwinCAT solution for the PLC library. Thus, the tests are available to all team members of a project. With the unit test framework, tests can also be extended by anyone, and existing tests can be started and easily evaluated.

Even though the term unit test framework is somewhat sophisticated for the PLC library TcUnit, it is evident that automated tests with only a few tools are also possible with the IEC 61131-3. Commercial unit test frameworks go far beyond what a PLC library can do. Thus, they contain dialogs to start the tests and display the results. Also, the areas in the source code that have been run through by the individual test cases are often marked.

Library TcUnit (TwinCAT 3.1.4022) on GitHub

Sample (TwinCAT 3.1.4022) on GitHub


The biggest obstacle in unit tests is often one’s weaker self. Once this has been overcome, the unit tests write themselves almost automatically. The second hurdle is the question which parts of the software have to be tested. It makes little sense to want to test everything. Instead, you should concentrate on essential areas of the software and test thoroughly the function blocks that form the basis of the application.

Basically, a unit test is considered to be fairly qualitative if possibly many branches are run through during execution. When writing unit tests, the test cases should be selected in such a way that as many branches of the function block as possible are run through.

If errors still occur in practice, it can be advantageous to write tests for this error case. This ensures that an error that has occurred once does not occur again.

The mere fact that two or more function blocks work correctly and this is proven by unit tests does not mean that an application also applies these function blocks correctly. Unit tests do not replace integration and acceptance tests in any way. Such test methods validate the overall system and evaluate it as a whole. Even though the unit test are applied, it is necessary to continue to test the entire work. However, a significant part of potential errors is eliminated in advance by unit tests, which saves time and money in the end.

Further Information

During the preparation for this post, Jakob Sagatowski published the first part of an article series on Test driven development in TwinCAT in his blog AllTwinCAT. For all those who want to go deeper into the topic, I can highly recommend the blog. It is encouraging that other PLC programmers also confront themselves with the testing of their software. The book The Art of Unit Testing by Roy Osherove is also a good introduction to the topic. Although the book was not written for IEC 61131-3, it contains some interesting approaches that can be implemented in the PLC without any problems.

Finally, I would like to thank my colleagues Birger Evenburg and Nils Johannsen. The basis for this post was a PLC library, kindly provided by them.

iec-61131-3 oop twincat codesys-v3 plc interfaces inheritance iec-61131-3-(english) methods
2 Meinungen
If your deadline for yourCustom Research Paper is near, seek forResearch Paper Assignment Help today for all your Research Paper Help Services.
Hey! For me writing is everything! I am professional writer and writing for me is a pleasure there is not task that I can't cope with. So my pleasure has returned into everyday work and now I produce papers for the orders. So I see that here on that blog lots of your do not know how to create good and that is so important qualified papers, you can rely on ,e and my https://essaysempire.com/ essay empire writing service.
Schreibe einen Kommentar:
methods iec-61131-3-(english) inheritance interfaces plc codesys-v3 twincat oop iec-61131-3
Entweder einloggen... ...oder ohne Wartezeit registrieren
Passwort wiederholen