Skip to content

How-to guide

Test clients

Test client logic in automated tests without a plant: start an OpcServer with test nodes in the same process and test against it.

This content was machine translated and may contain errors. Read in German

How-to guide

Test clients ​

The OPC UA .NET SDK contains both client and server. For automated tests, you can therefore start a server in the same process that contains exactly the nodes the client expects. You need neither a test plant nor an external simulator. The examples do not depend on a test framework. In xUnit, NUnit, or MSTest, the setup belongs in the test method or fixture, and the checks belong in its assertions.

Start the server and client in a test ​

Types usedOpcServerOpcClientOpcDataVariableNode

You create a server with nodes in one line: the constructor takes the address and the nodes. The test gets the identifier of a node from the node's Id property and does not have to build it. Two using blocks shut down the client and server even if a check fails:

csharp
var speedNode = new OpcDataVariableNode<int>("Speed", value: 100);
 
using (var server = new OpcServer("opc.tcp://localhost:48400/", speedNode))
using (var client = new OpcClient("opc.tcp://localhost:48400/")) {
    server.Start();
    client.Connect();
 
    OpcValue value = client.ReadNode(speedNode.Id);
 
    if ((int)value.Value != 100)
        throw new Exception("Unexpected speed.");
}
vbnet
Dim speedNode = New OpcDataVariableNode(Of Integer)("Speed", value:=100)

Using server = New OpcServer("opc.tcp://localhost:48400/", speedNode)
    Using client = New OpcClient("opc.tcp://localhost:48400/")
        server.Start()
        client.Connect()

        Dim value As OpcValue = client.ReadNode(speedNode.Id)

        If CInt(value.Value) <> 100 Then
            Throw New Exception("Unexpected speed.")
        End If
    End Using
End Using

Verify writes ​

Types usedOpcClientOpcStatusOpcDataVariableNode

Whatever the client writes ends up in the value of the node on the server. The test checks both the status of the write and the value in the node:

csharp
OpcStatus result = client.WriteNode(speedNode.Id, value: 120);
 
if (!result.IsGood || speedNode.Value != 120)
    throw new Exception("The value has not been written.");
vbnet
Dim result As OpcStatus = client.WriteNode(speedNode.Id, value:=120)

If Not result.IsGood OrElse speedNode.Value <> 120 Then
    Throw New Exception("The value has not been written.")
End If

Verify subscriptions ​

Types usedOpcClientOpcDataVariableNodeOpcDataChangeReceivedEventArgs

Notifications arrive asynchronously. The test changes the value on the server, reports the change with ApplyChanges, and waits for the notification with a timeout:

csharp
using (var received = new ManualResetEventSlim()) {
    client.SubscribeDataChange(speedNode.Id, (sender, e) => {
        if (e.Item.Value.As<int>() == 150)
            received.Set();
    });
 
    speedNode.Value = 150;
    speedNode.ApplyChanges(server.SystemContext);
 
    if (!received.Wait(TimeSpan.FromSeconds(5)))
        throw new Exception("No data change received.");
}
vbnet
Using received = New ManualResetEventSlim()
    client.SubscribeDataChange( _
            speedNode.Id, _
            Sub(sender, e)
                If e.Item.Value.As(Of Integer)() = 150 Then received.Set()
            End Sub)

    speedNode.Value = 150
    speedNode.ApplyChanges(server.SystemContext)

    If Not received.Wait(TimeSpan.FromSeconds(5)) Then
        Throw New Exception("No data change received.")
    End If
End Using

Verify method calls ​

Types usedOpcServerOpcObjectNodeOpcMethodNodeOpcClient

You can simulate methods that the client calls as an OpcMethodNode with a delegate on the test server. The return value of the delegate arrives at the client as the first output argument:

csharp
var machine = new OpcObjectNode("Machine");
var startJobNode = new OpcMethodNode(
        machine,
        name: "StartJob",
        new Func<string, int>(StartJob));
 
using (var server = new OpcServer("opc.tcp://localhost:48401/", machine))
using (var client = new OpcClient("opc.tcp://localhost:48401/")) {
    server.Start();
    client.Connect();
 
    object[] outputs = client.CallMethod(machine.Id, startJobNode.Id, "Job 1");
 
    if ((int)outputs[0] != 42)
        throw new Exception("Unexpected job number.");
}
...
private static int StartJob(string name)
{
    return 42;
}
vbnet
Dim machine = New OpcObjectNode("Machine")
Dim startJobNode = New OpcMethodNode( _
        machine, _
        name:="StartJob", _
        New Func(Of String, Integer)(AddressOf StartJob))

Using server = New OpcServer("opc.tcp://localhost:48401/", machine)
    Using client = New OpcClient("opc.tcp://localhost:48401/")
        server.Start()
        client.Connect()

        Dim outputs As Object() = client.CallMethod(machine.Id, startJobNode.Id, "Job 1")

        If CInt(outputs(0)) <> 42 Then
            Throw New Exception("Unexpected job number.")
        End If
    End Using
End Using
...
Private Shared Function StartJob(ByVal name As String) As Integer
    Return 42
End Function

Notes for test runs ​

TopicNote
PortsBy default, the server binds its port exclusively (UseExclusiveAddress). If tests run in parallel, each test needs its own port.
CertificatesOn first start, the server and client create their application certificates. This takes a few seconds. After that, both load their certificates from the certificate store.
TrustBy default, the server and client accept unknown certificates (AutoAcceptUntrustedCertificates), so tests do not need their own certificate management.
Cleanupusing reliably shuts down the client and server, even if a check fails.
LicenseWithout a license key, the SDK runs with the trial license for 30 minutes per application start. Long test runs therefore need the license key, see Set up the license.

The page Getting started of server development describes how to set up a server.