Further fixup & refactoring of Autofixture attribs
This now also includes reworking the attribute which activates Autofixture-style resolution upon an IServiceProvider. This has now been renamed to WithAutofixtureResolutionAttribute. The new/reworked attribute is composable with other Autofixture attributes.
This commit is contained in:
parent
f2b27480fc
commit
282c90f80f
|
|
@ -1,43 +0,0 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using AutoFixture;
|
||||
using AutoFixture.Kernel;
|
||||
using AutoFixture.Xunit2;
|
||||
using Elsa.Testing.Shared.AutoFixture.SpecimenBuilders;
|
||||
|
||||
namespace Elsa.Testing.Shared.AutoFixture.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Customizes the parameter so that it creates an <see cref="IServiceProvider"/>
|
||||
/// using Moq. That mock service provider gets services by resolving them from Autofixture.
|
||||
/// </summary>
|
||||
/// <seealso cref="AutofixtureServiceProviderSpecimenBuilder"/>
|
||||
public class AutofixtureServiceProviderAttribute : CustomizeAttribute
|
||||
{
|
||||
public override ICustomization GetCustomization(ParameterInfo parameter)
|
||||
=> new AutofixtureServiceProviderCustomization(parameter);
|
||||
|
||||
class AutofixtureServiceProviderCustomization : ICustomization
|
||||
{
|
||||
readonly ParameterInfo parameter;
|
||||
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
fixture.Customizations.Insert(0, GetSpecimenBuilder());
|
||||
}
|
||||
|
||||
ISpecimenBuilder GetSpecimenBuilder()
|
||||
{
|
||||
var paramSpec = new ParameterSpecification(parameter.ParameterType, parameter.Name);
|
||||
var specimenBuilder = new AutofixtureServiceProviderSpecimenBuilder();
|
||||
return new FilteringSpecimenBuilder(specimenBuilder, paramSpec);
|
||||
}
|
||||
|
||||
public AutofixtureServiceProviderCustomization(ParameterInfo parameter)
|
||||
{
|
||||
this.parameter = parameter;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ namespace Elsa.Testing.Shared.AutoFixture.Attributes
|
|||
|
||||
public ISpecimenBuilderNode Transform(ISpecimenBuilder builder)
|
||||
{
|
||||
return new Postprocessor(builder, new ElsaHostBuilderBuilderCommand(builderCustomizer), new IsAnElsaHostBuilderBuilderSpec());
|
||||
return new Postprocessor(builder, new ElsaHostBuilderBuilderCommand(builderCustomizer), IsInstanceOf.Type<ElsaHostBuilderBuilder>());
|
||||
}
|
||||
|
||||
public ElsaHostBuilderBuilderTransformation(Action<ElsaHostBuilderBuilder> builderCustomizer)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using AutoFixture;
|
||||
using AutoFixture.Xunit2;
|
||||
using Elsa.Testing.Shared.AutoFixture.Behaviors;
|
||||
using Elsa.Testing.Shared.AutoFixture.SpecimenBuilders;
|
||||
using Moq;
|
||||
|
||||
namespace Elsa.Testing.Shared.AutoFixture.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Customizes the parameter so that the <see cref="IServiceProvider"/>
|
||||
/// created by Moq will resolve services of the appropriate type, creating
|
||||
/// them using Autofixture.
|
||||
/// </summary>
|
||||
/// <seealso cref="AutofixtureServiceProviderSpecimenBuilder"/>
|
||||
public class WithAutofixtureResolutionAttribute : CustomizeAttribute
|
||||
{
|
||||
public override ICustomization GetCustomization(ParameterInfo parameter)
|
||||
=> new AutofixtureServiceProviderCustomization();
|
||||
|
||||
class AutofixtureServiceProviderCustomization : ICustomization
|
||||
{
|
||||
public void Customize(IFixture fixture)
|
||||
{
|
||||
var behavior = BehaviorFactory.GetPostprocessingBehavior<IServiceProvider>(AutofixtureResolutionServiceProviderSpecimenBuilder.AddAutofixtureResolution);
|
||||
fixture.Behaviors.Add(behavior);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using AutoFixture.Kernel;
|
||||
using Elsa.Testing.Shared.AutoFixture.Specifications;
|
||||
|
||||
namespace Elsa.Testing.Shared.AutoFixture.Behaviors
|
||||
{
|
||||
public class BehaviorFactory
|
||||
{
|
||||
public static ISpecimenBuilderTransformation GetPostprocessingBehavior<T>(Action<T,ISpecimenContext> postProcessingAction) where T : class
|
||||
=> new PostprocessingTransformation<T>(postProcessingAction);
|
||||
|
||||
public static ISpecimenBuilderTransformation GetPostprocessingBehavior<T>(Action<T> postProcessingAction) where T : class
|
||||
=> new PostprocessingTransformation<T>((speciman, ctx) => postProcessingAction(speciman));
|
||||
|
||||
class PostprocessingTransformation<T> : ISpecimenBuilderTransformation where T : class
|
||||
{
|
||||
readonly Action<T,ISpecimenContext> builderCustomizer;
|
||||
|
||||
public ISpecimenBuilderNode Transform(ISpecimenBuilder builder)
|
||||
{
|
||||
var command = new PostprocessingCommand<T>(builderCustomizer);
|
||||
var spec = IsInstanceOf.Type<T>();
|
||||
|
||||
return new Postprocessor(builder, command, spec);
|
||||
}
|
||||
|
||||
public PostprocessingTransformation(Action<T,ISpecimenContext> builderCustomizer)
|
||||
{
|
||||
this.builderCustomizer = builderCustomizer ?? throw new ArgumentNullException(nameof(builderCustomizer));
|
||||
}
|
||||
}
|
||||
|
||||
class PostprocessingCommand<T> : ISpecimenCommand where T : class
|
||||
{
|
||||
readonly Action<T,ISpecimenContext> builderCustomizer;
|
||||
|
||||
public void Execute(object specimen, ISpecimenContext context)
|
||||
{
|
||||
var builder = (T) specimen;
|
||||
builderCustomizer(builder, context);
|
||||
}
|
||||
|
||||
public PostprocessingCommand(Action<T,ISpecimenContext> builderCustomizer)
|
||||
{
|
||||
this.builderCustomizer = builderCustomizer ?? throw new ArgumentNullException(nameof(builderCustomizer));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
using AutoFixture.Kernel;
|
||||
using Elsa.Testing.Shared.Helpers;
|
||||
|
||||
namespace Elsa.Testing.Shared.AutoFixture.Specifications
|
||||
{
|
||||
public class IsAnElsaHostBuilderBuilderSpec : IRequestSpecification
|
||||
{
|
||||
public bool IsSatisfiedBy(object request) => request is ElsaHostBuilderBuilder;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using AutoFixture.Kernel;
|
||||
using Elsa.Testing.Shared.AutoFixture.SpecimenBuilders;
|
||||
|
||||
namespace Elsa.Testing.Shared.AutoFixture.Specifications
|
||||
{
|
||||
public class IsInstanceOf : IRequestSpecification
|
||||
{
|
||||
readonly Type type;
|
||||
|
||||
public bool IsSatisfiedBy(object request) => request.IsAnAutofixtureRequestForType(type);
|
||||
|
||||
public IsInstanceOf(Type type)
|
||||
{
|
||||
this.type = type ?? throw new ArgumentNullException(nameof(type));
|
||||
}
|
||||
|
||||
public static IsInstanceOf Type<T>() => new IsInstanceOf(typeof(T));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using AutoFixture.Kernel;
|
||||
using Moq;
|
||||
|
||||
namespace Elsa.Testing.Shared.AutoFixture.SpecimenBuilders
|
||||
{
|
||||
public class AutofixtureResolutionServiceProviderSpecimenBuilder : ISpecimenBuilder
|
||||
{
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
{
|
||||
if(!request.IsAnAutofixtureRequestForType<IServiceProvider>())
|
||||
return new NoSpecimen();
|
||||
|
||||
var provider = Mock.Of<IServiceProvider>();
|
||||
AddAutofixtureResolution(provider, context);
|
||||
return provider;
|
||||
}
|
||||
|
||||
public static void AddAutofixtureResolution(IServiceProvider provider, ISpecimenContext context)
|
||||
{
|
||||
var mock = Mock.Get(provider);
|
||||
|
||||
mock.Name = $"Autofixture_{nameof(IServiceProvider)}-{Guid.NewGuid()}";
|
||||
mock
|
||||
.Setup(x => x.GetService(It.IsAny<Type>()))
|
||||
.Returns((Type t) => context.Resolve(t));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
using System;
|
||||
using AutoFixture.Kernel;
|
||||
using Moq;
|
||||
|
||||
namespace Elsa.Testing.Shared.AutoFixture.SpecimenBuilders
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a mock <see cref="IServiceProvider"/> which gets services
|
||||
/// by resolving them from Autofixture.
|
||||
/// </summary>
|
||||
public class AutofixtureServiceProviderSpecimenBuilder : ISpecimenBuilder
|
||||
{
|
||||
public object Create(object request, ISpecimenContext context)
|
||||
{
|
||||
if(request.IsAnAutofixtureRequestForType<IServiceProvider>())
|
||||
return GetServiceProvider(context);
|
||||
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
static object GetServiceProvider(ISpecimenContext context)
|
||||
{
|
||||
var provider = new Mock<IServiceProvider>();
|
||||
|
||||
provider.Name = $"Autofixture_{nameof(IServiceProvider)}-{Guid.NewGuid()}";
|
||||
provider
|
||||
.Setup(x => x.GetService(It.IsAny<Type>()))
|
||||
.Returns((Type t) => context.Resolve(t));
|
||||
|
||||
return provider.Object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Elsa.Testing.Shared.AutoFixture.SpecimenBuilders
|
||||
|
|
@ -15,12 +16,21 @@ namespace Elsa.Testing.Shared.AutoFixture.SpecimenBuilders
|
|||
/// <param name="request">The request object</param>
|
||||
/// <typeparam name="T">The desired specimen type</typeparam>
|
||||
/// <returns><c>true</c> if the <paramref name="request"/> is a request for an instance of <typeparamref name="T"/>; <c>false</c> otherwise.</returns>
|
||||
public static bool IsAnAutofixtureRequestForType<T>(this object request)
|
||||
public static bool IsAnAutofixtureRequestForType<T>(this object request) => request.IsAnAutofixtureRequestForType(typeof(T));
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value which indicates if the specified <see cref="object"/> qualifies as an Autofixture
|
||||
/// request for an instance of the specified generic type.
|
||||
/// </summary>
|
||||
/// <param name="request">The request object</param>
|
||||
/// <param name="type">The desired specimen type</param>
|
||||
/// <returns><c>true</c> if the <paramref name="request"/> is a request for an instance of <typeparamref name="T"/>; <c>false</c> otherwise.</returns>
|
||||
public static bool IsAnAutofixtureRequestForType(this object request, Type type)
|
||||
{
|
||||
if(Equals(request, typeof(T)))
|
||||
if(Equals(request, type))
|
||||
return true;
|
||||
|
||||
if(request is ParameterInfo paramInfo && paramInfo.ParameterType == typeof(T))
|
||||
if(request is ParameterInfo paramInfo && paramInfo.ParameterType == type)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ namespace Elsa.Testing.Shared.AutoFixture.SpecimenBuilders
|
|||
}
|
||||
|
||||
static IServiceProvider GetServiceProvider(ISpecimenContext context)
|
||||
=> (IServiceProvider) new AutofixtureServiceProviderSpecimenBuilder().Create(typeof(IServiceProvider), context);
|
||||
=> (IServiceProvider) new AutofixtureResolutionServiceProviderSpecimenBuilder().Create(typeof(IServiceProvider), context);
|
||||
|
||||
static WorkflowExecutionContext GetWorkflowExecutionContext(ISpecimenContext context, IServiceProvider serviceProvider)
|
||||
=> new WorkflowExecutionContext(serviceProvider, Mock.Of<IWorkflowBlueprint>(), new WorkflowInstance());
|
||||
|
|
|
|||
|
|
@ -20,7 +20,11 @@ namespace Elsa.Testing.Shared.Helpers
|
|||
/// </summary>
|
||||
/// <param name="relativePath">The relative path, within the temporary folder.</param>
|
||||
/// <returns>A path for content within the temporary folder.</returns>
|
||||
public string GetContainedPath(string relativePath) => Path.Combine(Folder, relativePath);
|
||||
public string GetContainedPath(string relativePath)
|
||||
{
|
||||
Directory.CreateDirectory(Folder);
|
||||
return Path.Combine(Folder, relativePath);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ namespace Elsa.Services
|
|||
public class ActivityExecutionContextForActivityBlueprintFactoryTests
|
||||
{
|
||||
[Theory(DisplayName = "The CreateActivityExecutionContext method should create a context using the activity blueprint, the workflow execution context, cancellation token and injected service provider."), AutoMoqData]
|
||||
public void CreateActivityExecutionContextCreatesContextUsingBlueprintExecutionContextCancellationTokenAndServiceProvider([AutofixtureServiceProvider] IServiceProvider serviceProvider,
|
||||
public void CreateActivityExecutionContextCreatesContextUsingBlueprintExecutionContextCancellationTokenAndServiceProvider([WithAutofixtureResolution] IServiceProvider serviceProvider,
|
||||
IActivityBlueprint activityBlueprint,
|
||||
[OmitOnRecursion] WorkflowExecutionContext workflowExecutionContext,
|
||||
CancellationToken cancellationToken)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Elsa.Services.Models
|
|||
public class ActivityExecutionContextTests
|
||||
{
|
||||
[Theory(DisplayName = "The PurgeVariables method should clear the Variables instance associated with the WorkflowInstance associated with the Workflow Execution Context"), AutoMoqData]
|
||||
public void PurgeVariables_clears_workflow_execution_context_workflow_instance_variables([AutofixtureServiceProvider, Frozen] IServiceProvider serviceProvider,
|
||||
public void PurgeVariables_clears_workflow_execution_context_workflow_instance_variables([WithAutofixtureResolution, Frozen] IServiceProvider serviceProvider,
|
||||
[OmitOnRecursion,NoAutoProperties] ActivityExecutionContext sut,
|
||||
string variableName,
|
||||
object variableValue)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Elsa.Services.Models
|
|||
public class WorkflowExecutionContextTests
|
||||
{
|
||||
[Theory(DisplayName = "The PurgeVariables method should clear the Variables instance associated with the WorkflowInstance"), AutoMoqData]
|
||||
public void PurgeVariables_clears_workflow_execution_context_workflow_instance_variables([AutofixtureServiceProvider, Frozen] IServiceProvider serviceProvider,
|
||||
public void PurgeVariables_clears_workflow_execution_context_workflow_instance_variables([WithAutofixtureResolution, Frozen] IServiceProvider serviceProvider,
|
||||
[OmitOnRecursion,NoAutoProperties] WorkflowExecutionContext sut,
|
||||
string variableName,
|
||||
object variableValue)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace Elsa.Services
|
|||
public class WorkflowBuilderTests
|
||||
{
|
||||
[Theory(DisplayName = "The Build method should return a workflow blueprint with the WorkflowBurst persistence behaviour if no behaviour was specified"), AutoMoqData]
|
||||
public void BuildShouldReturnWorkflowBlueprintWithWorkflowBurstPersistenceBehaviourIfNoBehaviourSpecified([AutofixtureServiceProvider, Frozen] IServiceProvider serviceProvider,
|
||||
public void BuildShouldReturnWorkflowBlueprintWithWorkflowBurstPersistenceBehaviourIfNoBehaviourSpecified([WithAutofixtureResolution, Frozen] IServiceProvider serviceProvider,
|
||||
WorkflowBuilder sut,
|
||||
string idPrefix)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace Elsa.Services
|
|||
public class WorkflowExecutionContextForWorkflowBlueprintFactoryTests
|
||||
{
|
||||
[Theory(DisplayName = "The CreateWorkflowExecutionContextAsync method returns an execution context using the blueprint, an instance and the service provider"), AutoMoqData]
|
||||
public async Task CreateWorkflowExecutionContextAsyncReturnsContextWithBlueprintInstanceAndServiceProvider([AutofixtureServiceProvider] IServiceProvider serviceProvider,
|
||||
public async Task CreateWorkflowExecutionContextAsyncReturnsContextWithBlueprintInstanceAndServiceProvider([WithAutofixtureResolution] IServiceProvider serviceProvider,
|
||||
IWorkflowFactory workflowFactory,
|
||||
IWorkflowBlueprint workflowBlueprint,
|
||||
[OmitOnRecursion] WorkflowInstance instance)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ namespace Elsa.UnitTests.Triggers
|
|||
WorkflowTrigger trigger4,
|
||||
WorkflowTrigger trigger5,
|
||||
WorkflowTrigger trigger6,
|
||||
[AutofixtureServiceProvider] IServiceProvider serviceProvider,
|
||||
[WithAutofixtureResolution] IServiceProvider serviceProvider,
|
||||
[NoAutoProperties] WorkflowInstance workflowInstance)
|
||||
{
|
||||
Mock.Get(activityTypeService)
|
||||
|
|
|
|||
Loading…
Reference in a new issue