DotNetify.Testing 3.0.1

dotnet add package DotNetify.Testing --version 3.0.1
NuGet\Install-Package DotNetify.Testing -Version 3.0.1
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="DotNetify.Testing" Version="3.0.1" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add DotNetify.Testing --version 3.0.1
#r "nuget: DotNetify.Testing, 3.0.1"
#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 DotNetify.Testing as a Cake Addin
#addin nuget:?package=DotNetify.Testing&version=3.0.1

// Install DotNetify.Testing as a Cake Tool
#tool nuget:?package=DotNetify.Testing&version=3.0.1

<p align="center"><img width="350px" src="http://dotnetify.net/content/images/dotnetify-logo.png"></p>

NuGet

DotNetify-Testing

DotNetify-Testing provides a simple and effective way to unit-test dotNetify view models. It emulates the SignalR hub and client-side connections so you can write tests that closely mimic the way your application would interact with real clients in real-time.

Hub Emulator

Start by creating a new instance of HubEmulator through HubEmulatorBuilder:

var hubEmulator = new HubEmulatorBuilder()
  .Register<HelloWorldVM>(nameof(HelloWorldVM))
  .Build();

The builder methods are:

  • Register: register the view model types to test.
  • AddServices: add services or service stubs that are required by the registered view models.
  • UseMiddleware: add a dotNetify middleware to the emulated hub pipeline.
  • UseFilter: add a dotNetify filter to the emulated hub pipeline.

Example:

var hubEmulator = new HubEmulatorBuilder()
  .Register<HelloWorldVM>(nameof(HelloWorldVM))
  .AddServices(services =>
  {
    services.AddTransient<IMyService>(provider => myServiceStub);
  })
  .UseMiddleware<JwtBearerAuthenticationMiddleware>()
  .UseFilter<AuthorizeFilter>()
  .Build();

Hub Client

var client = hubEmulator.CreateClient();

A client represents a single hub connection. You can optionally assign a specific connection ID or a user identity to associate with the connection.

Connect to View Model

Connect the hub client to a view model as you would on a real client and get the initial state:

client.Connect(nameof(HelloWorldVM));
var state = client.GetState<IHelloWorldState>();

Assert.Equal("Hello World", state.Greetings);

The generic method GetState always returns the latest client state.

Client Dispatch

client.Connect(nameof(SimpleListVM));
client.Dispatch(new { Add = "Clive Lewis" });

var state = client.GetState<ISimpleListState>();

Assert.Contains(state.Employees, x => x.FullName == "Clive Lewis");

The Dispatch method has several overloads so it can accept either a dynamic object, a dictionary of objects, or a JSON-serialized string.

Checking Actual Responses

The previous example asserts on the client state after a dispatch. But if you want to assert on the actual server response, use the return value of the Dispatch:

var responses = client.Dispatch(new { Name = "Clive Lewis" });
var firstResponse = responses.As<IHelloWorldState>();

Assert("Hello Clive Lewis", firstResponse.Greetings);

Notice that the return type is actually a list of responses. Even though the call is synchronous, the underlying communication is not. It is possible that a view model can return multiple responses in a span of time the emulator is set to wait for responses. The default wait time is 1 second with maximum responses of 1, so by default it will always return with 0 or 1 response. You can change these settings on the client object itself:

client.ResponseTimeout = 2000; // in milliseconds.
client.MaxResponses = 10;

A response object contains raw data as produced by the server, which you can convert to a type with the As generic method.

Listening for Server Updates

If the responses are initiated by the server through PushUpdates, use the Listen method:

client.Connect(nameof(LiveChartVM));
var updates = client.Listen(5500);

Assert.Equal(5, updates.Count);

This method allows you to aggregate updates from the server with the span of time specified by the argument.

In some cases involving MulticastVM, you may want to check whether one client's action will trigger server updates to another client. Calling Listen right after the action runs a risk of a race condition. To ensure that it starts listening before the action takes place, you hae two options:

  1. Use the overload that accepts an action argument:
var client1 = _hubEmulator.CreateClient();
var client2 = _hubEmulator.CreateClient();

client1.Connect(nameof(ChatRoomVM));
client2.Connect(nameof(ChatRoomVM));

var client1Responses = client1.Listen(() =>
{
  client2.Dispatch(new { SendMessage = new { Text = "Hi", UserName = "Billy" } });
});

var response = client1Responses.As<IChatRoomState>();
Assert.Equal("Hi", response.Message.Text);
Assert.Equal("Billy", response.Message.UserName);
  1. Use the asynchronous overload:
var client1ResponsesTask = client1.ListenAsync();

client2.Dispatch(new { SendMessage = new { Text = "Hi", UserName = "Billy" } });

var client1Response = await client1ResponsesTask;

Client Destroy

To remove a client from the hub emulator, use the Destroy method.

client.Destroy();

Connect to Live Hub

You can use the same client API to connect to a live hub with LiveHub:

using (var client = await LiveHub.CreateClientAsync("https://my-webapp"))
{
  var responses = client.Connect(nameof(HelloWorldVM));
  var response = responses.As<IHelloWorldState>();
  Assert.Equal("Hello World", response.FullName);
}
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
3.0.1 361 1/2/2023
3.0.0 370 11/4/2022
2.0.4 465 2/9/2021
2.0.3 694 12/13/2020
1.1.0 1,069 7/23/2020
1.0.0 498 7/20/2020
0.3.1 806 11/28/2019
0.3.0 534 11/27/2019
0.2.0 581 11/19/2019