Unit testing NHibernate UserTypes - unit-testing

Does anyone have a good approach towards unit testing their UserTypes?
By way of example, I have an object in my model called DateRange, which has a DatePoint start and DatePoint end. In addition to making range type operations available for two DateTimes, these objects let me adjust the precision for the task at hand (i.e., Day, Hour, Minute, etc.). When stored to the db for an application I'm working on, I just need to store the start and end as DateTime, no nulls allowed. I can't think of how to map this without a UserType, so I have:
/// <summary>User type to deal with <see cref="DateRange"/> persistence for time sheet tracking.</summary>
public class TimePeriodType : IUserType
{
public SqlType[] SqlTypes {
get {
var types = new SqlType[2];
types[0] = new SqlType(DbType.DateTime);
types[1] = new SqlType(DbType.DateTime);
return types;
}
}
public Type ReturnedType
{
get { return typeof(DateRange); }
}
/// <summary>Just return <see cref="DateRange.Equals(object)"/></summary>
public new bool Equals(object x, object y)
{
return x != null && x.Equals(y);
}
/// <summary>Just return <see cref="DateRange.GetHashCode"/></summary>
public int GetHashCode(object x)
{
return x.GetHashCode();
}
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
var start = (DateTime)NHibernateUtil.DateTime.NullSafeGet(rs, names[0]);
var end = (DateTime)NHibernateUtil.DateTime.NullSafeGet(rs, names[1]);
return new DateRange(start, end, TimeSlice.Minute);
}
public void NullSafeSet(IDbCommand cmd, object value, int index) {
Check.RequireNotNull<DateRange>(value);
Check.RequireArgType<DateRange>(value);
var dateRange = ((DateRange)value);
NHibernateUtil.DateTime.NullSafeSet(cmd, dateRange.Start, index);
NHibernateUtil.DateTime.NullSafeSet(cmd, dateRange.End, index);
}
public object DeepCopy(object value) {
Check.RequireNotNull<DateRange>(value);
Check.RequireArgType<DateRange>(value);
var dateRange = ((DateRange) value);
return new DateRange(dateRange.Start, dateRange.End);
}
public bool IsMutable
{
get { return false; }
}
public object Replace(object original, object target, object owner) {
//because it is immutable so we can just return it as is
return original;
}
public object Assemble(object cached, object owner) {
//Used for caching, as it is immutable we can just return it as is
return cached;
}
public object Disassemble(object value) {
//Used for caching, as it is immutable we can just return it as is
return value;
}
}
}
Now I'm looking for a way to prove it works. Thanks in advance!
Cheers,
Berryl

I created a user type for System.Drawing.Color, and here is how I unit tested it with MSTest and Moq.
ColorUserType.cs:
public class ColorUserType : IUserType
{
public object Assemble( object cached, object owner )
{
return cached;
}
public object DeepCopy( object value )
{
return value;
}
public object Disassemble( object value )
{
return value;
}
public new bool Equals( object x, object y )
{
if(ReferenceEquals(x, y ) )
{
return true;
}
if( x == null || y == null )
{
return false;
}
return x.Equals( y );
}
public int GetHashCode( object x )
{
return x == null ? typeof( Color ).GetHashCode() + 473 : x.GetHashCode();
}
public bool IsMutable
{
get
{
return true;
}
}
public object NullSafeGet( IDataReader rs, string[] names, object owner )
{
var obj = NHibernateUtil.String.NullSafeGet( rs, names[0] );
if( obj == null )
{
return null;
}
return ColorTranslator.FromHtml( (string)obj );
}
public void NullSafeSet( IDbCommand cmd, object value, int index )
{
if( value == null )
{
( (IDataParameter)cmd.Parameters[index] ).Value = DBNull.Value;
}
else
{
( (IDataParameter)cmd.Parameters[index] ).Value = ColorTranslator.ToHtml( (Color)value );
}
}
public object Replace( object original, object target, object owner )
{
return original;
}
public Type ReturnedType
{
get
{
return typeof( Color );
}
}
public SqlType[] SqlTypes
{
get
{
return new[] { new SqlType( DbType.StringFixedLength ) };
}
}
}
ColorUserTypeTests.cs
[TestClass]
public class ColorUserTypeTests
{
public TestContext TestContext { get; set; }
[TestMethod]
public void AssembleTest()
{
var color = Color.Azure;
var userType = new ColorUserType();
var val = userType.Assemble( color, null );
Assert.AreEqual( color, val );
}
[TestMethod]
public void DeepCopyTest()
{
var color = Color.Azure;
var userType = new ColorUserType();
var val = userType.DeepCopy( color );
Assert.AreEqual( color, val );
}
[TestMethod]
public void DissasembleTest()
{
var color = Color.Azure;
var userType = new ColorUserType();
var val = userType.Disassemble( color );
Assert.AreEqual( color, val );
}
[TestMethod]
public void EqualsTest()
{
var color1 = Color.Azure;
var color2 = Color.Bisque;
var color3 = Color.Azure;
var userType = new ColorUserType();
var obj1 = (object)color1;
var obj2 = obj1;
Assert.IsFalse( userType.Equals( color1, color2 ) );
Assert.IsTrue( userType.Equals( color1, color1 ) );
Assert.IsTrue( userType.Equals( color1, color3 ) );
Assert.IsFalse( userType.Equals( color1, null ) );
Assert.IsFalse( userType.Equals( null, color1 ) );
Assert.IsTrue( userType.Equals( null, null ) );
Assert.IsTrue( userType.Equals( obj1, obj2 ) );
}
[TestMethod]
public void GetHashCodeTest()
{
var color = Color.Azure;
var userType = new ColorUserType();
Assert.AreEqual( color.GetHashCode(), userType.GetHashCode( color ) );
Assert.AreEqual( typeof( Color ).GetHashCode() + 473, userType.GetHashCode( null ) );
}
[TestMethod]
public void IsMutableTest()
{
var userType = new ColorUserType();
Assert.IsTrue( userType.IsMutable );
}
[TestMethod]
public void NullSafeGetTest()
{
var dataReaderMock = new Mock();
dataReaderMock.Setup( m => m.GetOrdinal( "white" ) ).Returns( 0 );
dataReaderMock.Setup( m => m.IsDBNull( 0 ) ).Returns( false );
dataReaderMock.Setup( m => m[0] ).Returns( "#ffffff" );
var userType = new ColorUserType();
var val = (Color)userType.NullSafeGet( dataReaderMock.Object, new[] { "white" }, null );
Assert.AreEqual( "ffffffff", val.Name, "The wrong color was returned." );
dataReaderMock.Setup( m => m.IsDBNull( It.IsAny() ) ).Returns( true );
Assert.IsNull( userType.NullSafeGet( dataReaderMock.Object, new[] { "black" }, null ), "The color was not null." );
dataReaderMock.VerifyAll();
}
[TestMethod]
public void NullSafeSetTest()
{
const string color = "#ffffff";
const int index = 0;
var mockFactory = new MockFactory( MockBehavior.Default );
var parameterMock = mockFactory.Create();
parameterMock.SetupProperty( p => p.Value, string.Empty );
var parameterCollectionMock = mockFactory.Create();
parameterCollectionMock.Setup( m => m[0] ).Returns( parameterMock.Object );
var commandMock = mockFactory.Create();
commandMock.Setup( m => m.Parameters ).Returns( parameterCollectionMock.Object );
var userType = new ColorUserType();
userType.NullSafeSet( commandMock.Object, ColorTranslator.FromHtml( color ), index );
Assert.AreEqual( 0, string.Compare( (string)( (IDataParameter)commandMock.Object.Parameters[0] ).Value, color, true ) );
userType.NullSafeSet( commandMock.Object, null, index );
Assert.AreEqual( DBNull.Value, ( (IDataParameter)commandMock.Object.Parameters[0] ).Value );
mockFactory.VerifyAll();
}
[TestMethod]
public void ReplaceTest()
{
var color = Color.Azure;
var userType = new ColorUserType();
Assert.AreEqual( color, userType.Replace( color, null, null ) );
}
[TestMethod]
public void ReturnedTypeTest()
{
var userType = new ColorUserType();
Assert.AreEqual( typeof( Color ), userType.ReturnedType );
}
[TestMethod]
public void SqlTypesTest()
{
var userType = new ColorUserType();
Assert.AreEqual( 1, userType.SqlTypes.Length );
Assert.AreEqual( new SqlType( DbType.StringFixedLength ), userType.SqlTypes[0] );
}
}

I was thinking I could mock / fake some of the dependencies here, but wound up deciding the best way to do this was by using a database.
Some things I learned along the way:
1) it's worth the effort when learning NHibernate techniques to have a dedicated set of tools including a way to quickly configure a db and test fixture for it (the same kinds of agile tools you'll need for everything else, really) and a dedicated test lab that you don't have an emotional investment in.
2) mocks do not lend themselves to interfaces you don't own, like IDataReader.
Cheers

Related

Mock DBSet<T> and call AsQueryable method return an empty list

I use entity framework core 6, XUnit for testing, Moq 4.16.1
I have a List, Mock it as DBSet<T>, I call AsQueryable method on DBSet<T> then return a empty list. If i mock AsQueryable method on DBSet<T>, i will have a expected list. Can you tell me Why?
This is my code
public static class MockDbExtensions
{
public static Mock<DbSet<T>> MockDbSet<T>(this IQueryable<T> testData) where T : class
{
Mock<DbSet<T>> dbSetMock = new Mock<DbSet<T>>();
dbSetMock.As<IQueryable<T>>().Setup(m => m.Provider).Returns(new TestAsyncQueryProvider<T>(testData.Provider));
dbSetMock.As<IQueryable<T>>().Setup(m => m.Expression).Returns(testData.Expression);
dbSetMock.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(testData.ElementType);
dbSetMock.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => testData.GetEnumerator());
dbSetMock.As<IAsyncEnumerable<T>>().Setup(m => m.GetAsyncEnumerator(default)).Returns(() => new TestAsyncEnumerator<T>(testData.GetEnumerator()));
return dbSetMock;
}
public static Mock<DbSet<T>> MockDbSet<T>(this IEnumerable<T> elements) where T : class
{
var testData = elements.AsQueryable();
return testData.MockDbSet();
}
public static Mock<DbSet<T>> MockDbSet<T>(this T[] elements) where T : class
{
var testData = elements.AsQueryable();
return testData.MockDbSet();
}
}
internal class TestAsyncQueryProvider<TEntity> : IAsyncQueryProvider
{
private readonly IQueryProvider _inner;
internal TestAsyncQueryProvider(IQueryProvider inner)
{
_inner = inner;
}
public IQueryable CreateQuery(Expression expression)
{
return new TestAsyncEnumerable<TEntity>(expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new TestAsyncEnumerable<TElement>(expression);
}
public object Execute(Expression expression)
{
return _inner.Execute(expression);
}
public TResult Execute<TResult>(Expression expression)
{
return _inner.Execute<TResult>(expression);
}
public IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression)
{
return new TestAsyncEnumerable<TResult>(expression);
}
public TResult ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken = new CancellationToken())
{
var expectedResultType = typeof(TResult).GetGenericArguments()[0];
var executionResult = ((IQueryProvider)this).Execute(expression);
return (TResult)typeof(Task).GetMethod(nameof(Task.FromResult))
.MakeGenericMethod(expectedResultType)
.Invoke(null, new[] { executionResult });
}
}
internal class TestAsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T>
{
public TestAsyncEnumerable(IEnumerable<T> enumerable)
: base(enumerable)
{ }
public TestAsyncEnumerable(Expression expression)
: base(expression)
{ }
public IAsyncEnumerator<T> GetEnumerator()
{
return new TestAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new TestAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
IQueryProvider IQueryable.Provider => new TestAsyncQueryProvider<T>(this);
}
internal class TestAsyncEnumerator<T> : IAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public TestAsyncEnumerator(IEnumerator<T> inner)
{
_inner = inner;
}
public void Dispose()
{
_inner.Dispose();
}
public T Current => _inner.Current;
public Task<bool> MoveNext(CancellationToken cancellationToken)
{
return Task.FromResult(_inner.MoveNext());
}
public ValueTask<bool> MoveNextAsync() => new ValueTask<bool>(_inner.MoveNext());
public ValueTask DisposeAsync()
{
_inner.Dispose();
return new ValueTask();
}
}
public class ReportTemplateServiceTests
{
private List<ReportTemplateType> CreateReportTemplateTypes()
{
return new List<ReportTemplateType>
{
new ReportTemplateType { Id = new Guid("144013ED-2D77-4572-8AB4-483C66E4EF1D"), Name = "Financial statements", DisplayOrder = 3, CmsId = 101475, IsActive = true },
new ReportTemplateType { Id = new Guid("058F8F85-A735-48F3-B526-79855FFF1EB0"), Name = "Reports", DisplayOrder = 1, CmsId = 100473, IsActive = true },
new ReportTemplateType { Id = new Guid("69D55B31-69BB-4BBC-82F1-A707B484E99B"), Name = "Letters", DisplayOrder = 2, CmsId = 100474, IsActive = true },
new ReportTemplateType { Id = new Guid("19D2650B-CE8E-4B54-95D9-ACAFA5C1CE40"), Name = "Custom working papers", DisplayOrder = 4, CmsId = 101476, IsActive = true },
};
}
public async void CreateReportTemplateAsync_Success()
{
// Arrange
var reportTemplates = CreateReportTemplates().MockDbSet().Object;
var a = reportTemplates.AsQueryable().ToList(); // return empty list after call AsQueryable()
}
}
I mock AsQueryable method on DBSet<T>, i will have a expected list.

How to use Moq in unit test that calls another method in same EF Repository

In my project I am using Repository.
I'm trying to unit test a SAVE method and return the call value via the Get method.
I'm having a Repository Query mockup issue when calling through the Get method. Can you help me in this case?
I Have a Class:
public class ClientRoleBo
{
private readonly IRepositoryBase<ClientRole> _repository;
public ClientRoleBo(IRepositoryBase<ClientRole> repository)
{
_repository = repository;
}
public Task<ClientRoleResp?> Get(Guid clientGuid, Guid id)
{
return Task.FromResult(
_repository.Query(x => x.Guid == id && x.ClientGuid == clientGuid && !x.IsDeleted)
.Select(x => new ClientRoleResp
{
Code = x.Code,
Guid = x.Guid,
IsActive = x.IsActive,
Name = x.Name
}).FirstOrDefault()
);
}
public async Task<ClientRole> Save(Guid clientGuid, Guid? guid, ClientRoleReq req)
{
ClientRole? data = null;
var existItem = _repository.Query(x => x.Code == req.Code && x.ClientGuid == clientGuid).FirstOrDefault();
if (existItem != null)
throw new HttpResponseException(400, "Exist clientrole");
data = new()
{
Code = req.Code,
Name = req.Name,
IsActive = req.IsActive,
ModifiedDate = DateTime.Now,
CreatedDate = DateTime.Now,
ClientGuid = clientGuid
};
await _repository.AddAsync(data);
return (await Get(clientGuid, data!.Guid))!;
}
}
I have a issue when code call method "Save" return data of method "Get" same Repository
My Mock Repository:
public class TestClientRole{
public static IRepositoryBase<TEntiy> MockRepo<TEntiy>(TEntiy[] data, Expression<Func<TEntiy, bool>> returnExpression = null) where TEntiy : class
{
var mock = new Mock<IRepositoryBase<TEntiy>>();
mock.Setup(x => x.Query(
It.IsAny<Expression<Func<TEntiy, bool>>>()
)).Returns(returnExpression != null ? data.AsQueryable().Where(returnExpression).AsEnumerable() : data.AsEnumerable());
return mock.Object;
}
[Fact]
public void Save()
{
var clientRoles = new ClientRole[]
{
new ClientRole
{
Code = "123",
Name = "Role1",
Guid = Guid.NewGuid(),
},
new ClientRole
{
Code = "1234",
Name = "Role2",
Guid = Guid.NewGuid(),
}
};
var mockRepo = MockRepo<ClientRole>(clientRoles, x => x.Guid == clientRoles[0].Guid);
var svc = new ClientRoleBo(mockRepo);
var res = svc.Save(Guid.NewGuid, null, new ClientRoleReq { Code = "Role", Name = "Role" }).GetAwaiter().GetResult();
Assert.True(res.Guid == clientRoles[0].Guid);
}
}

Unit testing generic htmlHelper methods with nunit

I'm new to nUnit and I've been tasked with creating unit tests for some htmlhelper extension methods.
How should I go about creating a unit test for the following method?
public static MvcHtmlString EnumDropDownListForOrderBy<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression, bool orderById, string firstElement = null, object htmlAttributes = null)
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
Type enumType = GetNonNullableModelType(metadata);
IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>();
IEnumerable<SelectListItem> items = values.Select(value => new SelectListItem()
{
Text = value.GetAttributeFrom<DescriptionAttribute>(value.ToString()).Description,
Value = value.ToString(),
Selected = value.Equals(metadata.Model)
});
IEnumerable<SelectListItem> itemsFiltered = items.Where(e => !string.IsNullOrEmpty(e.Text)).AsEnumerable();
itemsFiltered = itemsFiltered.OrderBy(e => (orderById ? e.Text : e.Value));
return htmlHelper.DropDownListFor(
expression,
itemsFiltered,
firstElement,
htmlAttributes
);
}
Any help would be appreciated
Below is how you write a Unit Test for this. Note that since you have not specified that you use a Mock object framework I'm going to the poor man technique, which is the hand written stubs and mocks. There is also another helper method if you are using Moq.
It is important to note that, in order to simplify the code execution I have made couple of changes to your extension method, so the test would not fail unexpectedly. Checking for any unexpected behaver is a good defensive programming practice anyway.
Back to the tests.
SUT (System Under Test)
This is how the SUT (System Under Test) looks like and supporting types looks like. (Please feel free to modify to your need accordingly)
public static class MyHtmlHelper
{
public static MvcHtmlString EnumDropDownListForOrderBy<TModel, TEnum>
(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TEnum>> expression,
bool orderById, string firstElement = null, object htmlAttributes = null,
Func<ModelMetadata> fromLambFunc = null)
{
ModelMetadata metadata =
ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
Type enumType = GetNonNullableModelType(metadata);
IEnumerable<TEnum> values = Enum.GetValues(enumType).Cast<TEnum>();
IEnumerable<SelectListItem> items =
values.Select(value => new SelectListItem()
{
Text = GetText(value),
Value = value.ToString(),
Selected = value.Equals(metadata.Model)
});
IEnumerable<SelectListItem> itemsFiltered =
items.Where(e => !string.IsNullOrEmpty(e.Text)).AsEnumerable();
itemsFiltered = itemsFiltered.OrderBy(e => (orderById ? e.Text : e.Value));
return htmlHelper.DropDownListFor
(expression, itemsFiltered, firstElement, htmlAttributes);
}
private static Type GetNonNullableModelType(ModelMetadata metadata) {
return typeof (SomeEnum);
}
private static string GetText<TEnum>(TEnum value) {
return value.GetAttributeFrom<DescriptionAttribute>(value.ToString()) != null
? value.GetAttributeFrom<DescriptionAttribute>(value.ToString()).Description
: string.Empty;
}
}
public static class ExtensionMethodsAttr
{
public static T GetAttributeFrom<T>(this object instance, string propertyName)
where T : Attribute
{
var attrType = typeof(T);
var property = instance.GetType().GetProperty(propertyName);
return property != null ?
(T)property.GetCustomAttributes(attrType, false).First() : default(T) ;
}
}
public enum SomeEnum { A,}
Unit Tests
[TestFixture]
public class HtmlHelperTests
{
[Test]
public void EnumDropDownListForOrderBy_InvokeDropDownListFor_ReturnsExpectedSelectItemResult()
{
//Arrange
var expected = "<select id=\"Foo\" name=\"Foo\"></select>";
var fakeHtmlHelper = CreateHtmlHelperStaticStubs
(new ViewDataDictionary(new FakeViewModel() {Foo = SomeEnum.A}));
//var fakeHtmlHelper = CreateHtmlHelperUsingMoq
(new ViewDataDictionary(new FakeViewModel(){Foo = SomeEnum.A}));
//Act
var result = fakeHtmlHelper.EnumDropDownListForOrderBy
(model => model.Foo, It.IsAny<bool>(), null, null, null);
//Assert
Assert.AreEqual(expected, result.ToString());
}
private static HtmlHelper<FakeViewModel>
CreateHtmlHelperStaticStubs(ViewDataDictionary viewData)
{
var stubControllerContext = new ControllerContext(new FakeHttpContext(), new RouteData(), new FakeController());
var stubViewContext = new ViewContext(stubControllerContext, new FakeView(),
new ViewDataDictionary(new FakeViewModel() { Foo = SomeEnum.A }),
new TempDataDictionary(), new TextMessageWriter());
var fakeViewDataContainer = new FakeViewDataContainer();
fakeViewDataContainer.ViewData = viewData;
return new HtmlHelper<FakeViewModel>(stubViewContext, fakeViewDataContainer);
}
//Moq version
private static HtmlHelper<FakeViewModel>
CreateHtmlHelperUsingMoq(ViewDataDictionary viewData)
{
var stubControllerContext = new Mock<ControllerContext>();
stubControllerContext.Setup(x => x.HttpContext).Returns(new Mock<HttpContextBase>().Object);
stubControllerContext.Setup(x => x.RouteData).Returns(new RouteData());
stubControllerContext.Setup(x => x.Controller).Returns(new Mock<ControllerBase>().Object); ;
var stubViewContext = new Mock<ViewContext>();
stubViewContext.Setup(x => x.View).Returns(new Mock<IView>().Object);
stubViewContext.Setup(x => x.ViewData).Returns(viewData);
stubViewContext.Setup(x => x.TempData).Returns(new TempDataDictionary());
var mockViewDataContainer = new Mock<IViewDataContainer>();
mockViewDataContainer.Setup(v => v.ViewData).Returns(viewData);
return new HtmlHelper<FakeViewModel>(stubViewContext.Object, mockViewDataContainer.Object);
}
}
class FakeHttpContext : HttpContextBase
{
private Dictionary<object, object> _items = new Dictionary<object, object>();
public override IDictionary Items { get { return _items; } }
}
class FakeViewDataContainer : IViewDataContainer
{
private ViewDataDictionary _viewData = new ViewDataDictionary();
public ViewDataDictionary ViewData { get { return _viewData; } set { _viewData = value; } }
}
class FakeController : Controller { }
class FakeView : IView
{
public void Render(ViewContext viewContext, System.IO.TextWriter writer)
{
throw new NotImplementedException();
}
}
public class FakeViewModel {
public SomeEnum Foo { get; set; }
}

How do I use Autofixture (v3) with ICustomization, ISpecimenBuilder to deal with constructor parameter?

I'm trying to overcome a scenario in which a class has a string constructor parameter which cannot be satisfied by any old string generated by Autofixture (the Guid-y looking value).
Before you're tempted to answer simply with a link to Mark Seemann's Ploeh blog entry on Convention-based Customizations, let me say that I've been referencing it and other blog entries of his for this test, which I can't get to pass.
When I step through in debug, I can see that at some point the constructor parameter is passed in with the valid value, but the test still fails with the Guid-y Color value. I think this has something to do with the fact that there is both a 'color' parameter value, and a 'Color' property to be populated by Autofixture. Is it that I've written an ISpecimenBuilder that addresses the constructor parameter, but I'm testing the public property value (two different things)?
I know that all this is overkill for the example, but I envision a more complicated scenario in which using the Build<T>().With() method would not be DRY.
The Failing Test
[Fact]
public void Leaf_Color_Is_Brown()
{
// arrange
var fixture = new Fixture().Customize(new LeafColorCustomization());
// act
var leaf = fixture.Create<Leaf>();
// using .Build<>.With(), test passes
//var leaf = fixture.Build<Leaf>().With(l => l.Color, "brown").CreateAnonymous();
// assert
Assert.True(leaf.Color == "brown");
}
The SUT
public class Leaf
{
public Leaf(string color)
{
if (color != "brown")
throw new ArgumentException(#"NO LEAF FOR YOU!");
this.Color = color;
}
public string Color { get; set; }
}
The CompositeCustomization implementation (I know the AutoMoqCustomization() isn't needed in this example)
public class LeafCustomization : CompositeCustomization
{
public LeafCustomization()
: base(
new LeafColorCustomization(),
new AutoMoqCustomization()) { }
}
The Leaf-specific ICustomization
public class LeafColorCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
if (fixture == null)
throw new ArgumentNullException("fixture");
fixture.Customizations.Add(new LeafBuilder());
}
}
The String-constructor-with-name-of-Color-specific ISpecimenBuilder
public class LeafBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var pi = request as ParameterInfo;
if (pi == null)
return new NoSpecimen(request);
if (pi.ParameterType != typeof(string) || pi.Name != "color")
return new NoSpecimen(request);
return "brown";
}
}
Solution 1:
Register that the Color writable property should not be assigned any automatic value as part of the post-processing:
internal class LeafColorCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<Leaf>(c => c
.Without(x => x.Color));
fixture.Customizations.Add(new LeafBuilder());
}
}
Solution 2:
Make the Color property read-only:
public class Leaf
{
private readonly string color;
public Leaf(string color)
{
if (color != "brown")
throw new ArgumentException(#"NO LEAF FOR YOU!");
this.color = color;
}
public string Color
{
get { return this.color; }
}
}
Since the Color property is read-only AutoFixture is not going to assign a value for it.
The above solutions apply also to AutoFixture 2.
Assuming you deal with the property setting stuff separately, here's a constructor argument restriction Customization which does the trick:
class BrownLeavesCustomization : ICustomization
{
void ICustomization.Customize( IFixture fixture )
{
Func<string> notBrownGenerator = fixture.Create<Generator<string>>()
.SkipWhile( x => x == "Brown" )
.First;
fixture.Customizations.Add(
ArgumentGeneratorCustomization<Leaf>.ForConstructorArgument(
"color",
notBrownGenerator ) );
}
static class ArgumentGeneratorCustomization<T>
{
public static ISpecimenBuilder ForConstructorArgument<TArg>( string argumentName, Func<TArg> generator )
{
return new ConstructorArgumentGenerator<TArg>( argumentName, generator );
}
class ConstructorArgumentGenerator<TArg> : ISpecimenBuilder
{
readonly string _argumentName;
readonly Func<TArg> _generator;
public ConstructorArgumentGenerator( string argumentName, Func<TArg> generator )
{
Assert.Contains( argumentName, from ctor in typeof( T ).GetConstructors() from param in ctor.GetParameters() select param.Name );
_argumentName = argumentName;
_generator = generator;
}
object ISpecimenBuilder.Create( object request, ISpecimenContext context )
{
var pi = request as ParameterInfo;
if ( pi == null )
return new NoSpecimen( request );
if ( pi.Member.DeclaringType != typeof( T ) )
return new NoSpecimen( request );
if ( pi.Member.MemberType != MemberTypes.Constructor )
return new NoSpecimen( request );
if ( pi.ParameterType != typeof( TArg ) )
return new NoSpecimen( request );
if ( pi.Name != _argumentName )
return new NoSpecimen( request );
return _generator();
}
}
}
}
Solution: (based on Mark Seemann's comment on this answer)
Accommodate both the constructor parameter and the writeable property in the ISpecimenBuilder implementation, and do nothing other than add the LeafBuilder instance in LeafColorCustomization:
public class LeafBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var paramInfo = request as ParameterInfo;
if (paramInfo != null
&& paramInfo.ParameterType == typeof(string)
&& paramInfo.Name == "color")
{ return "brown"; }
var propInfo = request as PropertyInfo;
if (propInfo != null
&& propInfo.PropertyType == typeof(string)
&& propInfo.Name == "Color")
{ return "brown"; }
return new NoSpecimen(request);
}
}
internal class LeafColorCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(new LeafBuilder());
}
}

Unit testing Monorail's RenderText method

I'm doing some maintenance on an older web application written in Monorail v1.0.3. I want to unit test an action that uses RenderText(). How do I extract the content in my test? Reading from controller.Response.OutputStream doesn't work, since the response stream is either not setup properly in PrepareController(), or is closed in RenderText().
Example Action
public DeleteFoo( int id )
{
var success= false;
var foo = Service.Get<Foo>( id );
if( foo != null && CurrentUser.IsInRole( "CanDeleteFoo" ) )
{
Service.Delete<Foo>( id );
success = true;
}
CancelView();
RenderText( "{ success: " + success + " }" );
}
Example Test (using Moq)
[Test]
public void DeleteFoo()
{
var controller = new FooController ();
PrepareController ( controller );
var foo = new Foo { Id = 123 };
var mockService = new Mock < Service > ();
mockService.Setup ( s => s.Get<Foo> ( foo.Id ) ).Returns ( foo );
controller.Service = mockService.Object;
controller.DeleteTicket ( foo.Id );
mockService.Verify ( s => s.Delete<Foo> ( foo.Id ) );
Assert.AreEqual ( "{success:true}", GetResponse ( Response ) );
}
// response.OutputStream.Seek throws an "System.ObjectDisposedException: Cannot access a closed Stream." exception
private static string GetResponse( IResponse response )
{
response.OutputStream.Seek ( 0, SeekOrigin.Begin );
var buffer = new byte[response.OutputStream.Length];
response.OutputStream.Read ( buffer, 0, buffer.Length );
return Encoding.ASCII.GetString ( buffer );
}
Override BaseControllerTest.BuildResponse() and provide your mock of IMockResponse built with Moq.