1
0
mirror of https://github.com/bitwarden/server.git synced 2025-01-05 19:17:36 +01:00

Enable testing of ASP.net MVC controllers

Controller properties have all kinds of validations in the background.
In general, we don't user properties on our Controllers, so the easiest
way to allow for Autofixture-based testing of our Controllers is to just
omit setting all properties on them.
This commit is contained in:
Matt Gibson 2021-10-29 18:37:37 -04:00
parent 3a11101c30
commit d08e9359af
4 changed files with 102 additions and 0 deletions

View File

@ -22,6 +22,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Api\Api.csproj" />
<ProjectReference Include="..\..\src\Core\Core.csproj" />
<ProjectReference Include="..\common\Common.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,38 @@
using AutoFixture;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc;
using Bit.Api.Controllers;
using AutoFixture.Kernel;
using System;
using Bit.Test.Common.AutoFixture;
using Org.BouncyCastle.Security;
namespace Bit.Api.Test.AutoFixture
{
/// <summary>
/// Disables setting of Auto Properties on the Controller to avoid ASP.net initialization errors. Still sets constructor dependencies.
/// </summary>
/// <param name="fixture"></param>
public class ControllerCustomization : ICustomization
{
private readonly Type _controllerType;
public ControllerCustomization(Type controllerType)
{
if (!controllerType.IsAssignableTo(typeof(Controller)))
{
throw new InvalidParameterException($"{nameof(controllerType)} must derive from {typeof(Controller).Name}");
}
_controllerType = controllerType;
}
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(new BuilderWithoutAutoProperties(_controllerType));
}
}
public class ControllerCustomization<T> : ICustomization where T : Controller
{
public void Customize(IFixture fixture) => new ControllerCustomization(typeof(T)).Customize(fixture);
}
}

View File

@ -0,0 +1,22 @@
using System;
using AutoFixture;
namespace Bit.Test.Common.AutoFixture.Attributes
{
/// <summary>
/// <para>
/// Base class for customizing parameters in methods decorated with the
/// Bit.Test.Common.AutoFixture.Attributes.MemberAutoDataAttribute.
/// </para>
/// ⚠ Warning ⚠ Will not insert customizations into AutoFixture's AutoDataAttribute build chain
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Parameter, AllowMultiple = true)]
public abstract class BitCustomizeAttribute : Attribute
{
/// <summary>
/// /// Gets a customization for the method's parameters.
/// </summary>
/// <returns>A customization for the method's paramters.</returns>
public abstract ICustomization GetCustomization();
}
}

View File

@ -0,0 +1,41 @@
using System;
using AutoFixture;
using AutoFixture.Dsl;
using AutoFixture.Kernel;
namespace Bit.Test.Common.AutoFixture
{
public class BuilderWithoutAutoProperties : ISpecimenBuilder
{
private readonly Type _type;
public BuilderWithoutAutoProperties(Type type)
{
_type = type;
}
public object Create(object request, ISpecimenContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var type = request as Type;
if (type == null || type != _type)
{
return new NoSpecimen();
}
var fixture = new Fixture();
// This is the equivalent of _fixture.Build<_type>().OmitAutoProperties().Create(request, context), but no overload for
// Build(Type type) exists.
dynamic reflectedComposer = typeof(Fixture).GetMethod("Build").MakeGenericMethod(_type).Invoke(fixture, null);
return reflectedComposer.OmitAutoProperties().Create(request, context);
}
}
public class BuilderWithoutAutoProperties<T> : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context) =>
new BuilderWithoutAutoProperties(typeof(T)).Create(request, context);
}
}