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.
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:
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.");
}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 UsingVerify 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:
OpcStatus result = client.WriteNode(speedNode.Id, value: 120);
if (!result.IsGood || speedNode.Value != 120)
throw new Exception("The value has not been written.");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 IfVerify 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:
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.");
}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 UsingVerify 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:
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;
}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 FunctionNotes for test runs
| Topic | Note |
|---|---|
| Ports | By default, the server binds its port exclusively (Use). If tests run in parallel, each test needs its own port. |
| Certificates | On 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. |
| Trust | By default, the server and client accept unknown certificates (Auto), so tests do not need their own certificate management. |
| Cleanup | using reliably shuts down the client and server, even if a check fails. |
| License | Without 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.

