Testing Middleware#
Testing middleware and the extensibility points generally requires access to the CommandContext
and AppConfig
.
Accessing CommandContext#
[Test]
public void SomeTest()
{
var result = new AppRunner<App>().RunInMem("some args");
var context = result.CommandContext;
}
public void SomeTest()
{
var result = new AppRunner<App>()
.Verify(new Scenario
{
When = {Args = "some args"},
Then =
{
// Action<CommandContext> to perform assertions
AssertContext = ctx => ...
}
});
var context = result.CommandContext;
}
Both RunInMem
and Verify
return a CommandContext to use for further assertions.
Verify also has the Scenario.Then.AssertContext callback for a more fluid syntax approach.
Accessing invocation values#
When your middleware can modify the invocation, such as parameter values and class instances, you'll want to access the invocation metadata to verify.
There are a few CommandContext extension methods to make this easier.
To get the InvocationStep, which contains the Command, Invocation and Instance, use:
GetCommandInvocationInfo()
to get the invocation of the command.GetCommandInvocationInfo<TCommandClass>()
to get the invocation of the command with the.Instance
typed asTCommandClass
.GetInterceptorInvocationInfo<TInterceptorClass>()
to get the invocation of the interceptor in the specified class with the.Instance
typed asTInterceptorClass
.
The InvocationInfo
includes the properties for InvocationStep and Invocation. The xml comments in the linked source files indicate which stage each property is loaded.
The InvocationInfo
properties ArgumentParameters
and ArgumentParameterValues
include only those parameters that define arguments. They do not include parameters of type InterceptorExecutionDelegate, CommandContext, IConsole or any other type configured as a parameter resolver. Those are available in via NonArgumentParameters
and NonArgumentParameterValues
The InvocationInfo
includes a WasInvoked
property. To use this, configure the AppRunner with .TrackInvocations()
. A friendly error message will remind you if your forget.
Example#
We'll start with the following WebClient with a single Download command and an interceptor method to authenticate commands. You can imagine there would be other commands like Upload, Post, Get, etc.
public class WebClient
{
public void Authenticate(InterceptorExecutionDelegate next,
string user, string pwd)
{
_client.Connect(user, pwd);
return next();
}
public void Download(string url, IConsole console)
{
_client.Find(filter).ForEach(i => console.Out.WriteLine(i.Id));
}
}
And then we can assert some values passed to the methods like this.
public class PipedInputTests
{
[Test]
public void SomeTest()
{
var result = new AppRunner<WebClient>()
.TrackInvocations()
.RunInMem("--user me --pwd shhhh Download http://all-the-internet.com");
var context = result.CommandContext;
var invocation = context.GetCommandInvocationInfo<WebClient>();
invocation.WasInvoked.Should().Be(true);
invocation.ArgumentParameterValues.First().Should()
.Be("http://all-the-internet.com");
invocation = context.GetInterceptorInvocationInfo<WebClient>()
invocation.WasInvoked.Should().Be(true);
invocation.ArgumentParameterValues.Should()
.Be(new []{"me", "shhhh"});
}
}
public void SomeTest()
{
new AppRunner<WebClient>()
.TrackInvocations()
.Verify(new Scenario
{
When = {Args = "--user me --pwd shhhh Download http://all-the-internet.com"},
Then =
{
AssertContext = ctx =>
{
var invocation = ctx.GetCommandInvocationInfo<WebClient>();
invocation.WasInvoked.Should().Be(true);
invocation.ArgumentParameterValues.First().Should()
.Be("http://all-the-internet.com");
invocation = ctx.GetInterceptorInvocationInfo<WebClient>()
invocation.WasInvoked.Should().Be(true);
invocation.ArgumentParameterValues.Should()
.Be(new []{"me", "shhhh"});
}
}
});
}
Tip
CommandDotNet has an extensive set of tests like this to verify all of it's features. You should only need to test invocations when verifying custom middleware.