Example: Time-dependent coffee machine - Manual - AxUnit-ST - AxUnit ST documentation package - AxUnit-ST,

AxUnit-ST CLI Tool (test)

Portfolio
SIMATIC AX
Product
AxUnit-ST
Software version
8.3.9
Edition
07/2025
Language
English (original)
Package Name
@ax/axunitst-docs

You have a function returning a value that depends on the datetime. If you implement this without Dependency Injection, the test results depend on the current time.

In the below example, it is a coffee machine that tells you if it's time for a coffee or not.

CLASS CoffeeMachine

        METHOD PUBLIC IsItCoffeeTime : BOOL
            VAR_TEMP
                currentTime : TIME_OF_DAY;
                hour : INT;
                systemTime : LDATE_AND_TIME;
            END_VAR

            // This line is responsible for the timing problem
            Siemens.Simatic.S71500.Clocks.GetSystemDateTime(systemTime);

            // Here we get only the time from the datetime
            SplitDateAndTime(
                value := systemTime,
                hour => hour
            );

            //the machine thinks it's unhealthy to drink coffee
            IF hour > 6 AND hour < 20 THEN
                IsItCoffeeTime := TRUE;
            ELSE
                IsItCoffeeTime := FALSE;
            END_IF;

        END_METHOD
    END_CLASS

A test for this function could look like this:

{TestFixture}
    CLASS CoffeeMachineTests

        VAR PROTECTED
            _coffeeMachine : CoffeeMachine;
        END_VAR

        // The result of this test varies dependent of the time when you start it
        {Test}
        METHOD PUBLIC IsItCoffeeTimeReturnsTrueWhenBetween6And20
            VAR_TEMP
                result : BOOL;
            END_VAR

            result := _coffeeMachine.IsItCoffeeTime();
            Assert.Equal(actual := result, expected := TRUE);

        END_METHOD
    END_CLASS

If you want to be independent of the current time during testing, you have to be in control of it. Especially, if this is a static function (like here) the problem gets even worse.

To overcome the problem, you have to introduce an abstraction layer around the time function and inject this into your coffeeMachine.

In the following example, we define an interface which declares a function that returns the current time. A class is implementing that interface and returns the current time from the system function. Now the coffeeMachine is not dependent on the static system time function anymore.

    // this interface defines a behavior of a class implementing it
    INTERFACE PUBLIC ISystemFunctions
        METHOD GetSystemDateAndTime : LDATE_AND_TIME
        END_METHOD
    END_INTERFACE

    // this class uses the above interface and encapsulates the dependency
    // to the static GetSystemDataTime function
    CLASS PUBLIC SystemFunctionsImpl IMPLEMENTS ISystemFunctions

        METHOD PUBLIC GetSystemDateAndTime : LDATE_AND_TIME
            VAR_TEMP
                systemTime : LDATE_AND_TIME;
            END_VAR

            Siemens.Simatic.S71500.Clocks.GetSystemDateTime(systemTime);
            GetSystemDateAndTime := systemTime;

        END_METHOD
    END_CLASS

    // this implementation of the coffee machine gets the instance of the class,
    // implementing ISystemFunctions from the outside.
    CLASS CoffeeMachine
        VAR PUBLIC
            SystemFunctions : ISystemFunctions;
        END_VAR

        METHOD PUBLIC IsItCoffeeTime : BOOL
            VAR_TEMP
                currentTime : TIME_OF_DAY;
                hour : INT;
            END_VAR

            SplitDateAndTime(
                value := SystemFunctions.GetSystemDateAndTime(),
                hour => hour
            );

            IF hour > 6 AND hour < 20 THEN
                IsItCoffeeTime := TRUE;
            ELSE
                IsItCoffeeTime := FALSE;
            END_IF;

        END_METHOD
    END_CLASS

Additionally, you have to implement a second class implementing that interface. This class will be used during testing and is able to return the values you define by setting SetSystemDateAndTime:

    CLASS PUBLIC SystemFunctionsMock IMPLEMENTS ISystemFunctions
       VAR PUBLIC
            SetSystemDateAndTime : LDATE_AND_TIME;
       END_VAR

        METHOD PUBLIC GetSystemDateAndTime : LDATE_AND_TIME
            GetSystemDateAndTime := SetSystemDateAndTime;
        END_METHOD
    END_CLASS

Now you can write your test like that:

{TestFixture}
    CLASS CoffeeMachineTests

        VAR PROTECTED
            _systemFnMock : SystemFunctionsMock;
            _coffeeMachine : CoffeeMachine;
        END_VAR

        //Example of how to write a test for the CoffeeMachine, where we dictate the time
        {Test}
        METHOD PUBLIC IsItCoffeeTimeReturnsTrueWhenBetween6And20
            VAR_TEMP
                result : BOOL;
            END_VAR

            //Setup -> set the desired testing time, instead of the real time, than give the mock to the class
            _systemFnMock.SetSystemDateAndTime := LDT#1980-01-23-13:14:33.123456;
            _coffeeMachine.SystemFunctions := _systemFnMock;

            //Test
            result := _coffeeMachine.IsItCoffeeTime();
            Assert.Equal(actual := result, expected := TRUE);
        END_METHOD

    END_CLASS

Now you can execute the test and control the time which is used for the calculation.