Skip to content

Commit

Permalink
Test framework now includes validators
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesRandall committed Mar 16, 2019
1 parent b8eaa7f commit ca15475
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 13 deletions.
3 changes: 2 additions & 1 deletion Source/FunctionMonkey.Testing/AbstractAcceptanceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ public virtual void AfterBuild(IServiceCollection serviceCollection, ICommandReg
public IServiceProvider ServiceProvider => _scaffold.ServiceProvider;

/// <summary>
/// A convenience property to provide easy access to the registered ICommandDispatcher
/// Provides access to the command dispatcher registered in the service provider but wrapped
/// in a decorator that implements validation.
/// </summary>
public ICommandDispatcher Dispatcher => _scaffold.Dispatcher;
}
Expand Down
25 changes: 17 additions & 8 deletions Source/FunctionMonkey.Testing/AcceptanceTestScaffold.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System;
using System.IO;
using System.Reflection;
using System.Threading;
using AzureFromTheTrenches.Commanding;
using AzureFromTheTrenches.Commanding.Abstractions;
using FunctionMonkey.Abstractions;
Expand All @@ -19,7 +18,7 @@ namespace FunctionMonkey.Testing
public class AcceptanceTestScaffold
{
private static bool _environmentVariablesRegistered = false;
private static object _loadingAppVariablesLock = new object();
private static readonly object LoadingAppVariablesLock = new object();

/// <summary>
/// Setup the scaffold with the default TestFunctionHostBuilder
Expand Down Expand Up @@ -77,12 +76,10 @@ public void Setup<TFunctionHostBuilder>(
beforeBuild?.Invoke(serviceCollection, commandRegistry);

functionAppConfiguration.Build(testFunctionHostBuilder);

afterBuild?.Invoke(serviceCollection, commandRegistry);

ServiceProvider = serviceCollection.BuildServiceProvider();

Dispatcher = ServiceProvider.GetService<ICommandDispatcher>();
}

/// <summary>
Expand All @@ -94,6 +91,7 @@ protected virtual void RegisterFunctionMonkeyMocks(IServiceCollection serviceCol
serviceCollection.AddTransient<ICommandClaimsBinder, CommandClaimsBinderMock>();
serviceCollection.AddTransient<IContextSetter, ContextManagerMock>();
serviceCollection.AddTransient<IContextProvider, ContextManagerMock>();
serviceCollection.AddTransient<ValidatingDispatcher>();
}

/// <summary>
Expand Down Expand Up @@ -131,7 +129,7 @@ public void AddEnvironmentVariables(string appSettingsPath, bool oneTimeOnly = t

private static void SetEnvironmentVariables(Stream appSettings, bool oneTimeOnly)
{
lock (_loadingAppVariablesLock)
lock (LoadingAppVariablesLock)
{
if (_environmentVariablesRegistered && oneTimeOnly)
{
Expand Down Expand Up @@ -171,9 +169,20 @@ private static void SetEnvironmentVariables(Stream appSettings, bool oneTimeOnly
public IServiceProvider ServiceProvider { get; private set; }

/// <summary>
/// A convenience property to provide easy access to the registered ICommandDispatcher
/// Provides access to the command dispatcher registered in the service provider but wrapped
/// in a decorator that implements validation.
/// </summary>
public ICommandDispatcher Dispatcher { get; private set; }
public ICommandDispatcher Dispatcher
{
get
{
//IValidator validator = ServiceProvider.GetService<IValidator>();
//ICommandDispatcher registeredDispatcher = ServiceProvider.GetService<ICommandDispatcher>();
//ValidatingDispatcher validatingDispatcher = new ValidatingDispatcher(registeredDispatcher, validator);
ValidatingDispatcher validatingDispatcher = ServiceProvider.GetService<ValidatingDispatcher>();
return validatingDispatcher;
}
}
}
}

7 changes: 3 additions & 4 deletions Source/FunctionMonkey.Testing/FunctionMonkey.Testing.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,23 @@

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Version>1.0.0</Version>
<Version>1.1.3</Version>
<Authors>James Randall</Authors>
<Company>James Randall</Company>
<Copyright></Copyright>
<PackageLicenseUrl>https://raw.githubusercontent.com/JamesRandall/AzureFromTheTrenches.Commanding/master/LICENSE</PackageLicenseUrl>
<RepositoryUrl>https://github.com/JamesRandall/FunctionMonkey.git</RepositoryUrl>
<PackageProjectUrl>https://functionmonkey.azurefromthetrenches.com/</PackageProjectUrl>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<AssemblyVersion>1.1.3.0</AssemblyVersion>
<FileVersion>1.1.3.0</FileVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.2.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\FunctionMonkey.Abstractions\FunctionMonkey.Abstractions.csproj" />
<ProjectReference Include="..\FunctionMonkey\FunctionMonkey.csproj" />
</ItemGroup>

Expand Down
1 change: 1 addition & 0 deletions Source/FunctionMonkey.Testing/TestFunctionHostBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public IFunctionHostBuilder DefaultHttpResponseHandler<TResponseHandler>() where

public IFunctionHostBuilder AddValidator<TValidator>() where TValidator : IValidator
{
_serviceCollection.AddTransient(typeof(IValidator), typeof(TValidator));
return this;
}

Expand Down
60 changes: 60 additions & 0 deletions Source/FunctionMonkey.Testing/ValidatingDispatcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using AzureFromTheTrenches.Commanding.Abstractions;
using AzureFromTheTrenches.Commanding.Abstractions.Model;
using FunctionMonkey.Abstractions.Validation;
using FunctionMonkey.Commanding.Abstractions.Validation;

namespace FunctionMonkey.Testing
{
public class ValidatingDispatcher : ICommandDispatcher
{
private readonly ICommandDispatcher _underlyingDispatcher;
private readonly IValidator _validator;

public ValidatingDispatcher(ICommandDispatcher underlyingDispatcher, IValidator validator)
{
_underlyingDispatcher = underlyingDispatcher;
_validator = validator;
}

public async Task<CommandResult<TResult>> DispatchAsync<TResult>(ICommand<TResult> command, CancellationToken cancellationToken = new CancellationToken())
{
Validate(command);

return await _underlyingDispatcher.DispatchAsync(command, cancellationToken);
}

public async Task<CommandResult> DispatchAsync(ICommand command, CancellationToken cancellationToken = new CancellationToken())
{
Validate(command);
return await _underlyingDispatcher.DispatchAsync(command, cancellationToken);
}

public ICommandExecuter AssociatedExecuter { get; }

private void Validate(ICommand command)
{
// The .Validate method uses its generic parameter to determine the type of the
// command as it uses generics with the IServiceCollecton, this has the unfortunate
// side-effect of meaning you can't ask it to validate a none-concretely typed ICommand
// This isn't an issue in Function Monkey itself as we have the specific command type
// but does cause a problem here as if we call .Validate(command) command will be resolved
// as being of type ICommand and so no validator will be found.
//
// To work round this we construct a method call using the concrete type of the command.
// In test code this isn't performance sensitive so we don't bother compiling an expression
// for it.
MethodInfo methodInfo = _validator.GetType().GetMethod("Validate");
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(command.GetType());
ValidationResult validationResult = (ValidationResult)genericMethodInfo.Invoke(_validator, new [] {command});

//ValidationResult validationResult = _validator.Validate(command);
if (!validationResult.IsValid)
{
throw new ValidationException(validationResult);
}
}
}
}
15 changes: 15 additions & 0 deletions Source/FunctionMonkey.Testing/ValidationException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;
using FunctionMonkey.Commanding.Abstractions.Validation;

namespace FunctionMonkey.Testing
{
public class ValidationException : Exception
{
public ValidationException(ValidationResult validationResult)
{
ValidationResult = validationResult;
}

public ValidationResult ValidationResult { get; }
}
}

0 comments on commit ca15475

Please sign in to comment.