AutoFixture/AutoMoq+;AutoMoq接口方法未返回NUnit AutoData冻结对象
使用AutoMoqCustomization,我本希望我的测试能够正常工作,但失败了 这就是测试:AutoFixture/AutoMoq+;AutoMoq接口方法未返回NUnit AutoData冻结对象,nunit,autofixture,automoq,Nunit,Autofixture,Automoq,使用AutoMoqCustomization,我本希望我的测试能够正常工作,但失败了 这就是测试: [Test, AutoMoqData] public void Test1( [Frozen] MyObject myObject, [Frozen] Mock<IRepo> stubMock, MyClass sut, int objectId) { myObject.Id = objectId; MyObject result
[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));
}
[测试,自动烟雾数据]
公共无效测试1(
[冻结]MyObject MyObject,
[冻结]Mock stubMock,
我的类sut,
int objectId)
{
myObject.Id=objectId;
MyObject结果=sut.GetById(objectId);
Assert.That(result.Id,Is.EqualTo(myObject.Id));
}
如果我添加一行代码,我就可以让它工作。但我不想这样做,因为它应该被推断出来
stubMock.Setup(r => r.GetObject(It.IsAny<int>())).Returns(() => myObject);
stubMock.Setup(r=>r.GetObject(It.IsAny())。返回(()=>myObject);
MyClass有一个带有IRepo的构造函数。这是一种魅力,因为如果我在测试中使用上面的行,我就通过了测试
通常我在编写测试时不使用自动数据,这会使测试更加冗长:
[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));
}
[测试]
公共无效测试3()
{
IFixture fixture=新夹具();
int objectId=fixture.Create();
var stubMock=fixture.Freeze();
Setup(r=>r.GetObject(It.IsAny())。返回(()=>fixture.Create());
fixture.Freeze(customise=>customise.With(d=>d.Id,objectId));
var sut=新的MyClass(stubMock.Object);
MyObject结果=sut.GetById(objectId);
Assert.That(result.Id,Is.EqualTo(objectId));
}
所以我的代码已经干净多了,但我喜欢上面的最后一个樱桃:)有什么想法吗
如何运行:
添加Nuget包:
<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>
完整代码:
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));
}
}
公共类automoqdata属性:AutoDataAttribute
{
公共automoqdata属性()
:底座(新夹具()。自定义(新自动moqcustomization())
{
}
}
[测试夹具]
公共班级1
{
公共接口IRepo
{
MyObject获取对象(int-id);
}
公共类MyObject
{
公共int Id{get;set;}
}
公共类MyClass
{
专用只读IRepo_测试;
公共MyClass(IRepo测试){u test=test;}
公共MyObject GetById(int id){return_test.GetObject(id);}
}
[测试,自动烟雾数据]
公共无效测试1(
[冻结]MyObject MyObject[冻结]IRepo stubMock,MyClass sut,int objectId)
{
myObject.Id=objectId;
//由于myObject上的冻结属性,是否希望此注释行是自动的?
//Mock.Get(stubMock.Setup)(r=>r.GetObject(It.IsAny())。返回(()=>myObject);
MyObject结果=sut.GetById(objectId);
Assert.That(result.Id,Is.EqualTo(myObject.Id));
}
[测试,自动烟雾数据]
公开无效测试2(
[冻结]MyObject MyObject[冻结]Mock stubMock,MyClass sut,int objectId)
{
myObject.Id=objectId;
//由于myObject上的冻结属性,是否希望此注释行是自动的?
//Setup(r=>r.GetObject(It.IsAny())。返回(()=>myObject);
MyObject结果=sut.GetById(objectId);
Assert.That(result.Id,Is.EqualTo(myObject.Id));
}
[测试]
公共无效测试3()
{
IFixture fixture=新夹具();
int objectId=fixture.Create();
var stubMock=fixture.Freeze();
Setup(r=>r.GetObject(It.IsAny())。返回(()=>fixture.Create());
fixture.Freeze(customise=>customise.With(d=>d.Id,objectId));
var sut=新的MyClass(stubMock.Object);
MyObject结果=sut.GetById(objectId);
Assert.That(result.Id,Is.EqualTo(objectId));
}
}
感谢@MarkSeemann给我的一些提示,我找到了这个“问题”的解决方案
我的想法
我从AutoFixture.AutoMoq nuget包中的MockRelay类开始。我创建了一个重载MockRelayExtras,并将其添加到AutoMoqCustomization中
这将在接口或抽象类上进行反射,并相应地设置模拟
前
更新的MockRelay类
从3.20.0开始,您可以使用
AutoConfiguredMoqCustomization
。这将自动配置所有模拟,以便其成员的返回值由AutoFixture生成
将设置虚拟方法/属性/索引器,以便使用AutoFixture惰性地生成其返回值。如果该方法有out
参数,也将设置这些参数
公共字段和密封属性的值将被急切地设置
该测试现在应通过:
[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));
}
相关:您基本上看到了这个问题的含义:github.com/AutoFixture/AutoFixture/issues/176@MarkSeemann啊,tnx,这打开了一个可能性。它可能适用于单返回类型。我将测试它是否在多个服务器上工作。有没有办法获取用于自动数据的夹具?您可以将其作为方法参数来请求…@MarkSeemann哇,谢谢!我没有想到这一点。我明天会查看它,并为这个线程添加一个有效的解决方案。我将在github上更新这个代码:很好!我会抛下我的解决方案。
<?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
{
}
[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));
}