Reputation: 33
Using the AutoMoqCustomization i would have hoped my test would work but it fails.
this is the test:
[Test, AutoMoqData]
public void Test1(
[Frozen] MyObject myObject,
[Frozen] Mock<IRepo> stubMock,
MyClass sut,
int objectId)
{
myObject.Id = objectId;
MyObject result = sut.GetById(objectId);
Assert.That(result.Id, Is.EqualTo(myObject.Id));
}
i can get this to work if i add one line of code. But i would like not to have to do this because it should be inferred??
stubMock.Setup(r => r.GetObject(It.IsAny<int>())).Returns(() => myObject);
The MyClass has a constructor with the IRepo. This is working like a charm because if i use the line above in my test i have a passed test.
usually i write my test without the auto data it a lot more verbose:
[Test]
public void Test3()
{
IFixture fixture = new Fixture();
int objectId = fixture.Create<int>();
var stubMock = fixture.Freeze<Mock<IRepo>>();
stubMock.Setup(r => r.GetObject(It.IsAny<int>())).Returns(() => fixture.Create<MyObject>());
fixture.Freeze<MyObject>(customise => customise.With(d => d.Id, objectId));
var sut = new MyClass(stubMock.Object);
MyObject result = sut.GetById(objectId);
Assert.That(result.Id, Is.EqualTo(objectId));
}
So already my code is much cleaner but idd like that last cherry on top :) Any Idea's???
How to run:
Add Nuget packages:
<packages>
<package id="AutoFixture" version="3.19.2" targetFramework="net45" />
<package id="AutoFixture.AutoMoq" version="3.19.2" targetFramework="net45" />
<package id="AutoFixture.NUnit2" version="3.19.2" targetFramework="net45" />
<package id="Moq" version="3.1.416.3" targetFramework="net45" />
<package id="NUnit" version="2.6.3" targetFramework="net45" />
</packages>
Full Code:
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(new Fixture().Customize(new AutoMoqCustomization()))
{
}
}
[TestFixture]
public class Class1
{
public interface IRepo
{
MyObject GetObject(int id);
}
public class MyObject
{
public int Id { get; set; }
}
public class MyClass
{
private readonly IRepo _test;
public MyClass(IRepo test) { _test = test; }
public MyObject GetById(int id) { return _test.GetObject(id); }
}
[Test, AutoMoqData]
public void Test1(
[Frozen] MyObject myObject, [Frozen] IRepo stubMock, MyClass sut, int objectId)
{
myObject.Id = objectId;
// expecting this commented line to be automatic because of the Frozen attribute on myObject?
// Mock.Get(stubMock).Setup(r => r.GetObject(It.IsAny<int>())).Returns(() => myObject);
MyObject result = sut.GetById(objectId);
Assert.That(result.Id, Is.EqualTo(myObject.Id));
}
[Test, AutoMoqData]
public void Test2(
[Frozen] MyObject myObject, [Frozen] Mock<IRepo> stubMock, MyClass sut, int objectId)
{
myObject.Id = objectId;
// expecting this commented line to be automatic because of the Frozen attribute on myObject?
// stubMock.Setup(r => r.GetObject(It.IsAny<int>())).Returns(() => myObject);
MyObject result = sut.GetById(objectId);
Assert.That(result.Id, Is.EqualTo(myObject.Id));
}
[Test]
public void Test3()
{
IFixture fixture = new Fixture();
int objectId = fixture.Create<int>();
var stubMock = fixture.Freeze<Mock<IRepo>>();
stubMock.Setup(r => r.GetObject(It.IsAny<int>())).Returns(() => fixture.Create<MyObject>());
fixture.Freeze<MyObject>(customise => customise.With(d => d.Id, objectId));
var sut = new MyClass(stubMock.Object);
MyObject result = sut.GetById(objectId);
Assert.That(result.Id, Is.EqualTo(objectId));
}
}
Upvotes: 3
Views: 2339
Reputation: 68670
As of 3.20.0, you can use AutoConfiguredMoqCustomization
. This will automatically configure all mocks so that their members' return values are generated by AutoFixture.
Virtual methods/properties/indexers will be setup to lazily generate their return values using AutoFixture. If the method has out
parameters, those will be setup as well.
Public fields and sealed properties will have their values set eagerly.
This test should pass now:
[Test, AutoMoqData]
public void Test1(
[Frozen] MyObject myObject,
MyClass sut,
int objectId)
{
myObject.Id = objectId;
MyObject result = sut.GetById(objectId);
Assert.That(result.Id, Is.EqualTo(myObject.Id));
}
Upvotes: 3
Reputation: 33
Thanks to @MarkSeemann for some hints i am getting to a solution to this 'problem'.
I started out With the MockRelay class in the AutoFixture.AutoMoq nuget package. I created an overload MockRelayExtras and i add that to the AutoMoqCustomozation.
What this will do is reflect on the interface or abstract class and setup the mock accordingly
ex.
Mock.Get(TInterface.Instance)
.Setup( i => i.Method( It.IsAny<TParamType>() ) )
.Returns( () => fixture.Create<TMethodResult>() );
For now this will only work for Interfaces and Abstract classes ( without constructors )
Its a start. The code will need some cleaning up though. Furthermore i hope other people will like, enjoy and use this?
Happy coding!
this is a working solution with sort of basis test proving it works.
( this fixes resharper en test runner )
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Moq" publicKeyToken="69f491c39445e920" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.1408.717" newVersion="4.2.1408.717" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="nunit.core.interfaces" publicKeyToken="96d09a1eb7f44a77" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.3.13283" newVersion="2.6.2.12296" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
<packages>
<package id="AutoFixture" version="3.19.2" targetFramework="net45" />
<package id="AutoFixture.AutoMoq" version="3.19.2" targetFramework="net45" />
<package id="AutoFixture.NUnit2" version="3.19.2" targetFramework="net45" />
<package id="Moq" version="4.2.1408.0717" targetFramework="net45" />
<package id="NUnit" version="2.6.3" targetFramework="net45" />
</packages>
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(new Fixture().Customize(new AutoMoqCustomization(new MockRelayExtras())))
{
}
}
public class MockRelayExtras : MockRelay, ISpecimenBuilder
{
public new object Create(object request, ISpecimenContext context)
{
object result = base.Create(request, context);
var requestType = request as Type;
if (requestType != null && result != null)
{
SetupMockWithInterface(requestType, result, context);
}
return result;
}
public static void SetupMockWithInterface(Type requestType, object result, ISpecimenContext context)
{
typeof (MockRelayExtras).GetMethod("SetupMockWithInterfaceGeneric")
.MakeGenericMethod(requestType).Invoke(null, new[] {result, context});
}
public static void SetupMockWithInterfaceGeneric<TType>(TType result, ISpecimenContext context)
where TType : class
{
//Mock.Get(stubMock).Setup(r => r.GetObject(It.IsAny<int>())).Returns(() => myObject);
Mock<TType> genericMock = Mock.Get(result);
foreach (MethodInfo methodInfo in typeof (TType).GetMethods())
{
// ISetup<TType,TMethodResult> setup = genericMock.Setup<TType,TMethodResult>( methodInfo )
object setup =
typeof (MockRelayExtras).GetMethod("SetupAsGenericFunc")
.MakeGenericMethod(typeof (TType), methodInfo.ReturnType)
.Invoke(null, new object[] {methodInfo, genericMock});
// setup.Returns( () => context.Create<TResult>() )
typeof (MockRelayExtras).GetMethod("SetupReturnsAsGenericFunc")
.MakeGenericMethod(typeof (TType), methodInfo.ReturnType)
.Invoke(null, new[] {setup, context});
}
}
public static ISetup<TMock, TResult> SetupAsGenericFunc<TMock, TResult>(MethodInfo method, Mock<TMock> mock)
where TMock : class
{
ParameterExpression input = Expression.Parameter(typeof (TMock));
ParameterInfo[] parameters = method.GetParameters();
Expression<Func<TMock, TResult>> setup = null;
if (parameters.Length > 0)
{
IEnumerable<MethodCallExpression> properties =
parameters.Select(
pi => Expression.Call(typeof (It), "IsAny", new[] {pi.ParameterType}, new Expression[0]));
setup = Expression.Lambda<Func<TMock, TResult>>(
Expression.Call(input, method, properties), input);
}
else
{
setup = Expression.Lambda<Func<TMock, TResult>>(
Expression.Call(input, method), input);
}
return mock.Setup(setup);
}
public static void SetupReturnsAsGenericFunc<TMock, TResult>(ISetup<TMock, TResult> setup,
ISpecimenContext context)
where TMock : class
{
setup.Returns(() => context.Create<TResult>());
}
}
[TestFixture]
public class MockRelayExtrasTests
{
public class RelayTestClass
{
public int Id { get; set; }
}
public class RandomInputData
{
public int Prop1 { get; set; }
public string Prop2 { get; set; }
}
public interface ISingleResultNoInput
{
RelayTestClass SingleResultNoInput();
IEnumerable<RelayTestClass> ListResultNoInput();
RelayTestClass GetItemById(int id);
RelayTestClass GetItemById(int id, string randomSearch);
RelayTestClass GetItemBySearch(RandomInputData data);
}
[Test, AutoMoqData]
public void Create_AutoMockInterfaceIEnumerableResults_InterfaceIsSetupWithIEnumerable(
[Frozen] RelayTestClass itemTemplate,
[Frozen] ISingleResultNoInput sut,
[Frozen] IFixture fixture
)
{
List<RelayTestClass> result = sut.ListResultNoInput().ToList();
Assert.That(result[0], Is.EqualTo(itemTemplate));
}
[Test, AutoMoqData]
public void Create_AutoMockInterfaceMethodsAutoMoqData_InterfaceIsSetup(
[Frozen] RelayTestClass frozenItem, [Frozen] ISingleResultNoInput sut, int expectedId)
{
frozenItem.Id = expectedId;
RelayTestClass result = sut.SingleResultNoInput();
Assert.That(result.Id, Is.EqualTo(expectedId));
}
[Test, AutoMoqData]
public void Create_AutoMockInterfaceMethodParameter_InterfaceIsSetup(
[Frozen] RelayTestClass frozenItem, [Frozen] ISingleResultNoInput sut, int id)
{
frozenItem.Id = id;
RelayTestClass result = sut.GetItemById(id);
Assert.That(result.Id, Is.EqualTo(id));
}
[Test, AutoMoqData]
public void Create_AutoMockInterfaceMethodsAutoMoqDataMultipleInput_InterfaceIsSetup(
[Frozen] RelayTestClass frozenItem, [Frozen] ISingleResultNoInput sut, int id, string searchString)
{
frozenItem.Id = id;
RelayTestClass result = sut.GetItemById(id, searchString);
Assert.That(result.Id, Is.EqualTo(id));
}
[Test, AutoMoqData]
public void Create_AutoMockInterfaceMethodsAutoMoqDataComplexInput_InterfaceIsSetup(
[Frozen] RelayTestClass frozenItem, [Frozen] ISingleResultNoInput sut, RandomInputData input)
{
frozenItem.Id = input.Prop1;
RelayTestClass result = sut.GetItemBySearch(input);
Assert.That(result.Id, Is.EqualTo(input.Prop1));
}
}
[NUnitAddin]
public class LocalAddin : Addin
{
}
Upvotes: 0