Last active
August 29, 2015 14:12
-
-
Save hoetz/940a975e8f1238f156a0 to your computer and use it in GitHub Desktop.
aspnet vNext + Autofixture + NSubstitute (Bonus: setup for MVC Controllers)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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