Skip to content

Instantly share code, notes, and snippets.

@hoetz
Last active August 29, 2015 14:12
Show Gist options
  • Save hoetz/940a975e8f1238f156a0 to your computer and use it in GitHub Desktop.
Save hoetz/940a975e8f1238f156a0 to your computer and use it in GitHub Desktop.
aspnet vNext + Autofixture + NSubstitute (Bonus: setup for MVC Controllers)
using Web.Controllers;
using Web.Model;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Http;
using Xunit;
public class HomeTests
{
[Theory]
[AutoDomainData]
public void Index_OnGet_ReturnsCorrectViewModel(HomeController sut)
{
ViewResult result= sut.Index() as ViewResult;
Assert.True(result.ViewData.Model is StartPageViewModel);
}
}
//
//project.json of test project
//
{
"dependencies": {
"Xunit.KRunner": "1.0.0-rc1",
"NSubstitute":"1.8.0",
"ManagementWeb": "",
"Microsoft.AspNet.Mvc": "6.0.0-*",
"AutoFixture":"3.22-*",
"AutoFixture.AutoNSubstitute":"3.22-*"
},
"configurations": {
"net45": {},
"k10": {}
},
"commands": {
"test": "Xunit.KRunner"
}
}
//infrastructure ripped out from AF sources
using System;
using System.Reflection;
namespace Ploeh.AutoFixture.Xunit
{
/// <summary>
/// Base class for customizing parameters in methods decorated with
/// <see cref="AutoDataAttribute"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true)]
public abstract class CustomizeAttribute : Attribute
{
/// <summary>
/// Gets a customization for a parameter.
/// </summary>
/// <param name="parameter">The parameter for which the customization is requested.</param>
/// <returns></returns>
public abstract ICustomization GetCustomization(ParameterInfo parameter);
}
}
//
//
//
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Routing;
using NSubstitute;
using Ploeh.AutoFixture;
using Ploeh.AutoFixture.AutoNSubstitute;
using Ploeh.AutoFixture.Kernel;
using Ploeh.AutoFixture.Xunit;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Xunit.Sdk;
public class AutoDomainDataAttribute : AutoDataAttribute
{
public AutoDomainDataAttribute()
: base(new Fixture()
.Customize(new DomainCustomization())
.Customize(new MvcCustomization()))
{
}
public class DomainCustomization : CompositeCustomization
{
public DomainCustomization()
: base(
new AutoNSubstituteCustomization())
{
}
}
private class MvcCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Register<ViewDataDictionary>(() => new ViewDataDictionary(new EmptyModelMetadataProvider(),
new ModelStateDictionary()));
fixture.Register<ActionContext>(() => new ActionContext(Substitute.For<HttpContext>(), new RouteData(), new ActionDescriptor()));
}
}
}
namespace Ploeh.AutoFixture.Xunit
{
/// <summary>
/// Provides auto-generated data specimens generated by AutoFixture as an extention to
/// xUnit.net's Theory attribute.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
[CLSCompliant(false)]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "This attribute is the root of a potential attribute hierarchy.")]
public class AutoDataAttribute : DataAttribute
{
private readonly IFixture fixture;
/// <summary>
/// Initializes a new instance of the <see cref="AutoDataAttribute"/> class.
/// </summary>
/// <remarks>
/// <para>
/// This constructor overload initializes the <see cref="Fixture"/> to an instance of
/// <see cref="Fixture"/>.
/// </para>
/// </remarks>
public AutoDataAttribute()
: this(new Fixture())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AutoDataAttribute"/> class with an
/// <see cref="IFixture"/> of the supplied type.
/// </summary>
/// <param name="fixtureType">The type of the composer.</param>
/// <exception cref="ArgumentException">
/// <paramref name="fixtureType"/> does not implement <see cref="IFixture"/>
/// or does not have a default constructor.
/// </exception>
public AutoDataAttribute(Type fixtureType)
: this(AutoDataAttribute.CreateFixture(fixtureType))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AutoDataAttribute"/> class with the
/// supplied <see cref="IFixture"/>.
/// </summary>
/// <param name="fixture">The fixture.</param>
public AutoDataAttribute(IFixture fixture)
{
if (fixture == null)
{
throw new ArgumentNullException("fixture");
}
this.fixture = fixture;
}
/// <summary>
/// Gets the fixture used by <see cref="GetData"/> to create specimens.
/// </summary>
public IFixture Fixture
{
get { return this.fixture; }
}
/// <summary>
/// Gets the type of <see cref="Fixture"/>.
/// </summary>
public Type FixtureType
{
get { return this.Fixture.GetType(); }
}
/// <summary>
/// Returns the data to be used to test the theory.
/// </summary>
/// <param name="methodUnderTest">The method that is being tested</param>
/// <param name="parameterTypes">The types of the parameters for the test method</param>
/// <returns>The theory data generated by <see cref="Fixture"/>.</returns>
public override IEnumerable<object[]> GetData(MethodInfo methodUnderTest)
{
if (methodUnderTest == null)
{
throw new ArgumentNullException("methodUnderTest");
}
var specimens = new List<object>();
foreach (var p in methodUnderTest.GetParameters())
{
this.CustomizeFixture(p);
var specimen = this.Resolve(p);
specimens.Add(specimen);
}
return new[] { specimens.ToArray() };
}
private void CustomizeFixture(ParameterInfo p)
{
var dummy = false;
var customizeAttributes = p.GetCustomAttributes(typeof(CustomizeAttribute), dummy).OfType<CustomizeAttribute>();
foreach (var ca in customizeAttributes)
{
var c = ca.GetCustomization(p);
this.Fixture.Customize(c);
}
}
private object Resolve(ParameterInfo p)
{
var context = new SpecimenContext(this.Fixture);
return context.Resolve(p);
}
private static IFixture CreateFixture(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
if (!typeof(IFixture).IsAssignableFrom(type))
{
throw new ArgumentException(
string.Format(
CultureInfo.CurrentCulture,
"{0} is not compatible with IFixture. Please supply a Type which implements IFixture.",
type),
"type");
}
var ctor = type.GetConstructor(Type.EmptyTypes);
if (ctor == null)
{
throw new ArgumentException(
string.Format(
CultureInfo.CurrentCulture,
"{0} has no default constructor. Please supply a a Type that implements IFixture and has a default constructor. Alternatively you can supply an IFixture instance through one of the AutoDataAttribute constructor overloads. If used as an attribute, this can be done from a derived class.",
type),
"type");
}
return (IFixture)ctor.Invoke(null);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment