dsian.TwinCAT.Ads.Server.Mock 0.5.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package dsian.TwinCAT.Ads.Server.Mock --version 0.5.0
NuGet\Install-Package dsian.TwinCAT.Ads.Server.Mock -Version 0.5.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="dsian.TwinCAT.Ads.Server.Mock" Version="0.5.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add dsian.TwinCAT.Ads.Server.Mock --version 0.5.0
#r "nuget: dsian.TwinCAT.Ads.Server.Mock, 0.5.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install dsian.TwinCAT.Ads.Server.Mock as a Cake Addin
#addin nuget:?package=dsian.TwinCAT.Ads.Server.Mock&version=0.5.0

// Install dsian.TwinCAT.Ads.Server.Mock as a Cake Tool
#tool nuget:?package=dsian.TwinCAT.Ads.Server.Mock&version=0.5.0

build

dsian.TwinCAT.Ads.Server.Mock

Mocking a TwinCAT Ads Server, for unit testing code with ADS read/write requests.
With this Nuget package it is possible to test your code even if it is relying on TwinCAT.Ads.dll calls and dependencies on that library (e.g. TwinCAT.Ads.TypeSystem.SymbolFactory).
You don't need to setup a PLC or TwinCAT runtime to test your code, hence no special requirements on a build server.


How to

  1. Setup mocking server

    ushort port = 12345;
    string portName = "MyTestAdsServer";
    using (var mockServer = new Mock(port, portName))   // ILogger optional
    {
        // ...
    }
    
  2. Register Behaviors

     mockServer.RegisterBehavior(new ReadIndicationBehavior(1, 123,  Enumerable.Range(1,32).Select(i => (byte)i).ToArray()))
             .RegisterBehavior(new ReadIndicationBehavior(1, 1, Encoding.UTF8.GetBytes("acting as a ADS server")))
             .RegisterBehavior(new ReadIndicationBehavior(0, 0, null, AdsErrorCode.DeviceAccessDenied))
             .RegisterBehavior(new WriteIndicationBehavior(0, 0, 22));
    
    • Behaviors
      Behaviros like ReadIndicationBehavior are used as enpdpoint for a specific ADS call, e.g.
      new ReadIndicationBehavior(1, 123,  Enumerable.Range(1,32).Select(i => (byte)i).ToArray())
      
      A ReadAsync ADS call is made to IndexGroup=1, IndexOffset=123 with Length=32, in this case the server will return 32 bytes (0x01..0x20) to the client.
  3. Test
    For example, the class we want to test:

    using System;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace Sample
    {
        public class MyAdsClass
        {
            public MyAdsClass(int port)
            {
                Port = port;
            }
            public int Port { get; }
    
            private byte[] _buffer = new byte[32];
    
            public async Task<byte[]> GetValuesFilteredAsync(uint ig, uint io, Func<byte, bool> filterFunc)
            {
                using (var client = new TwinCAT.Ads.AdsClient())
                {
                    client.Connect(Port);
                    var result = await client.ReadAsync(ig, io, _buffer, CancellationToken.None);
                    if (result.Succeeded)
                        return _buffer.Where(x => filterFunc(x)).Select(x => x).ToArray();
                }
                return new byte[0];
            }
        }
    }
    

    Unit test:

    [TestMethod]
    public async Task Should_filter_even_and_odd_values()
    {
        // arrange
        ushort port = 12345;
        string portName = "MyTestAdsServer";
        using (var mockServer = new Mock(port, portName))   // ILogger optional
        {
            mockServer.RegisterBehavior(new ReadIndicationBehavior(1, 123, Enumerable.Range(1, 32).Select(i => (byte)i).ToArray()));
            var myAdsCls = new MyAdsClass(mockServer.ServerAddress.Port);
    
            // act
            var even = await myAdsCls.GetValuesFilteredAsync(1, 123, (x) => x % 2 == 0);
            var odd = await myAdsCls.GetValuesFilteredAsync(1, 123, (x) => x % 2 != 0);
    
            // assert
            Assert.IsTrue(even.SequenceEqual(new byte[] { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32 }));
            Assert.IsTrue(odd.SequenceEqual(new byte[] { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31 }));
        }
    }
    

Example

// setup mocking server
ushort port = 12345;
string portName = "MyTestAdsServer";
using (var mockServer = new Mock(port, portName))
{
    var serverBuffer = new byte[65535];
    mockServer.RegisterBehavior(new ReadIndicationBehavior(1, 123,  Enumerable.Range(1,32).Select(i => (byte)i).ToArray()))
                .RegisterBehavior(new ReadIndicationBehavior(1, 1, Encoding.UTF8.GetBytes("acting as a ADS server")))
                .RegisterBehavior(new ReadIndicationBehavior(0, 0, null, AdsErrorCode.DeviceAccessDenied))
                .RegisterBehavior(new WriteIndicationBehavior(0, 0, 22));

    Console.WriteLine("Server up and running");

    // now the actual Ads Read/WriteRequests...

    // create TwinCAT Ads client
    using (var client = new AdsClient(logger))
    {
        // connect to our mocking server
        client.Connect(port);
        if (client.IsConnected)
        {
            var readBuffer = new byte[65535];
            var readMemory = new Memory<byte>(readBuffer);
            var writeBuffer = new byte[65535];
            var writeMemory = new Memory<byte>(writeBuffer);

            // 1st behavior
            var resRd = await client.ReadAsync(1, 123, readMemory[..32], CancellationToken.None);
            // 2nd behavior
            resRd = await client.ReadAsync(1, 1, readMemory, CancellationToken.None);
            Console.WriteLine(Encoding.UTF8.GetString(readMemory.Slice(0,resRd.ReadBytes).Span));
            // 3rd behavior
            resRd = await client.ReadAsync(0, 0, readMemory, CancellationToken.None);
            // 4th behavior
            var resWr = await client.WriteAsync(0, 0, writeMemory[..22], CancellationToken.None);
        }
    }
}

See SampleConsole and UnitTestSample for functional examples.

Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on dsian.TwinCAT.Ads.Server.Mock:

Package Downloads
dsian.TwinCAT.Ads.Server.Mock.Extensions

Some extension methods for dsian.TwinCAT.Ads.Server.Mock

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
0.7.1 1,293 1/19/2023
0.7.0 485 11/26/2022
0.6.1 470 11/26/2022
0.6.0 441 11/26/2022
0.5.1 499 3/18/2022
0.5.0 657 1/7/2021