如何解决Moq + Autofixture:对依赖属性使用 Setup 清除整个模拟对象
我使用的是 Moq 和 AutoFixture。
给定以下接口:
public interface Int1
{
Int2 Int2 { get; }
}
public interface Int2
{
string Prop1 { get; }
string Prop2 { get; }
}
我正在执行以下测试:
using AutoFixture;
using AutoFixture.automoq;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
[TestClass]
public class TestClass
{
[TestMethod]
public void Test1()
{
var f = new Fixture().Customize(new automoqCustomization { ConfigureMembers = true });
var obj = f.Create<Mock<Int1>>();
obj.Object.Int2.Prop1.Should().NotBeNullOrEmpty();
obj.Object.Int2.Prop2.Should().NotBeNullOrEmpty();
}
[TestMethod]
public void Test2()
{
var f = new Fixture().Customize(new automoqCustomization { ConfigureMembers = true });
var obj = f.Create<Mock<Int1>>();
obj.Setup(q => q.Int2.Prop1).Returns("test");
obj.Object.Int2.Prop1.Should().Be("test");
obj.Object.Int2.Prop2.Should().NotBeNullOrEmpty();
}
}
第一个测试通过而第二个测试失败:Expected obj.Object.Int2.Prop2 not to be <null> or empty,but found <null>
。似乎在 Int2
的一个依赖属性上使用 Setup 时,它会清除整个 Int2
对象(将所有属性设置为默认值)。这是为什么?如何避免?
obj.Object
如下所示:
但是在执行 Setup
之后它看起来像这样(Prop2
是 null
):
有趣的是,当我在创建后访问 Int2
属性时,它工作正常。所以这个测试通过了(变量 int2
没有在任何地方使用):
[TestMethod]
public void Test2()
{
var f = new Fixture().Customize(new automoqCustomization { ConfigureMembers = true });
var obj = f.Create<Mock<Int1>>();
var int2 = obj.Object.Int2;
obj.Setup(q => q.Int2.Prop1).Returns("test");
obj.Object.Int2.Prop1.Should().Be("test");
obj.Object.Int2.Prop2.Should().NotBeNullOrEmpty();
}
有什么想法吗?
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<packagereference Include="AutoFixture" Version="4.15.0" />
<packagereference Include="AutoFixture.automoq" Version="4.15.0" />
<packagereference Include="FluentAssertions" Version="5.10.3" />
<packagereference Include="Microsoft.NET.Test.Sdk" Version="16.9.1" />
<packagereference Include="Moq" Version="4.16.1" />
<packagereference Include="MSTest.TestAdapter" Version="2.1.2" />
<packagereference Include="MSTest.TestFramework" Version="2.1.2" />
</ItemGroup>
</Project>
解决方法
简而言之,在为 Int2
属性设置返回值后,您最终会得到一个不同的 Prop1
属性模拟实例。为了满足您的请求,Moq 将生成一个新的模拟,它将返回 Prop1
的预期值。
您可以将其视为等效于以下测试:
[Fact]
public void Test3()
{
var obj2 = new Mock<IInterfaceB>();
obj2.Setup(x => x.Property1).Returns(Guid.NewGuid().ToString());
obj2.Setup(x => x.Property2).Returns(Guid.NewGuid().ToString());
var obj = new Mock<IInterfaceA>();
obj.Setup(x => x.PropertyB).Returns(obj2.Object);
obj.Setup(q => q.PropertyB.Property1).Returns("test");
Assert.Equal("test",obj.Object.PropertyB.Property1);
Assert.NotEmpty(obj.Object.PropertyB.Property2);
}
如果您想保留您的初始模拟实例并只更改 Prop1
,那么您可以使用 Mock.Get<T>(T)
。
[Fact]
public void Test4()
{
var f = new Fixture().Customize(new AutoMoqCustomization { ConfigureMembers = true });
var obj = f.Create<Mock<IInterfaceA>>();
var obj2 = Mock.Get(obj.Object.PropertyB);
obj2.Setup(q => q.Property1).Returns("test");
Assert.Equal("test",obj.Object.PropertyB.Property1);
Assert.NotEmpty(obj.Object.PropertyB.Property2);
}
但我会推荐使用 AutoFixture 的冻结功能
[TestMethod]
public void Test5()
{
var fixture = new Fixture()
.Customize(new AutoMoqCustomization { ConfigureMembers = true });
var int2Mock = fixture.Freeze<Mock<Int2>>();
var int1Mock = fixture.Create<Mock<Int1>>();
int2Mock.Setup(q => q.Prop1).Returns("test");
int1Mock.Object.Int2.Prop1.Should().Be("test");
int1Mock.Object.Int2.Prop2.Should().NotBeNullOrEmpty();
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。