Zum Inhalt springen

Anleitung

Clients testen

Client-Logik in automatisierten Tests ohne Anlage prüfen: einen OpcServer mit Test-Nodes im selben Prozess starten und gegen ihn testen.

Anleitung

Clients testen ​

Das OPC UA .NET SDK enthält Client und Server. Für automatisierte Tests lässt sich deshalb im selben Prozess ein Server starten, der genau die Nodes enthält, die der Client erwartet. Dafür brauchen Sie weder eine Testanlage noch einen externen Simulator. Die Beispiele sind unabhängig vom Testframework. In xUnit, NUnit oder MSTest gehört der Aufbau in die jeweilige Testmethode oder Fixture, die Prüfung in deren Assertions.

Server und Client im Test starten ​

Beteiligte TypenOpcServerOpcClientOpcDataVariableNode

Ein Server mit Nodes entsteht in einer Zeile: Der Konstruktor nimmt die Adresse und die Nodes entgegen. Den Identifier eines Nodes kennt der Test über die Eigenschaft Id des Nodes und muss ihn nicht selbst zusammensetzen. Zwei using-Blöcke beenden Client und Server auch dann, wenn eine Prüfung fehlschlägt:

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

Schreiben prüfen ​

Beteiligte TypenOpcClientOpcStatusOpcDataVariableNode

Was der Client schreibt, steht danach im Wert des Nodes auf dem Server. Der Test prüft beides, den Status des Schreibvorgangs und den Wert im 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

Subscriptions prüfen ​

Beteiligte TypenOpcClientOpcDataVariableNodeOpcDataChangeReceivedEventArgs

Benachrichtigungen treffen asynchron ein. Der Test ändert den Wert auf dem Server, meldet die Änderung mit ApplyChanges und wartet mit einer Obergrenze auf die Benachrichtigung:

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

Methodenaufrufe prüfen ​

Beteiligte TypenOpcServerOpcObjectNodeOpcMethodNodeOpcClient

Methoden, die der Client aufruft, lassen sich auf dem Testserver als OpcMethodNode mit einem Delegaten nachbilden. Der Rückgabewert des Delegaten kommt beim Client als erstes Ausgabeargument an:

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

Hinweise für Testläufe ​

ThemaHinweis
PortsDer Server bindet seinen Port standardmäßig exklusiv (UseExclusiveAddress). Wenn Tests parallel laufen, braucht jeder Test einen eigenen Port.
ZertifikateBeim ersten Start erzeugen Server und Client ihr Anwendungszertifikat. Das dauert einige Sekunden. Danach laden beide ihre Zertifikate aus dem Zertifikatspeicher.
VertrauenServer und Client nehmen unbekannte Zertifikate standardmäßig an (AutoAcceptUntrustedCertificates), Tests brauchen deshalb keine eigene Zertifikatsverwaltung.
Aufräumenusing beendet Client und Server zuverlässig, auch bei einer fehlgeschlagenen Prüfung.
LizenzOhne Lizenzschlüssel läuft das SDK in der Evaluation je Anwendungsstart 30 Minuten. Lange Testläufe brauchen deshalb den Lizenzschlüssel, siehe Lizenz einrichten.

Den Aufbau eines Servers beschreibt die Seite Erste Schritte der Server-Entwicklung.