这里是关于我们的技术开发环境的信息:
.NET 核心 3.1
PostgreSQL 14.2,由 Visual C++ build 1914 编译,64 位
EntityFramework.Functions 版本=1.5.0
Microsoft.EntityFrameworkCore.Design 版本=5.0.17
Microsoft.EntityFrameworkCore.Tools 版本=5.0.17
Npgsql.EntityFrameworkCore.PostgreSQL 版本=5.0.10
在我的应用程序中,我有一个Generic Target Class,它对应的是Wrapper类和Wrapper接口。
public class TargetWrapper<T> : ITargetWrapper<T>
{
private Target<T> _target;
public TargetWrapper()
{
_target = new Target<T>();
}
protected internal TargetWrapper(Target<T> target)
{
_target = target;
}
public T Data
{
get { return _target.Data; }
set { _target.Data = value; }
}
}
我有一个名为
JohnDoeClass
的业务逻辑类具有以下代码,该代码使用 TargetWrapper 将泛型类型设置为动态:
public class JohnDoeClass
{
public EmailRecord MaryDoeMethod(ITargetWrapper<dynamic> targetWrapper)
{
var dataset = targetWrapper.Data.someDynamicMetaDataEntity;
return new BlahEntity()
{
Id = dataset ["id"],
FaxId = dataset["fax_id"],
FaxNumber = dataset["fax_number"],
FaxLocation = dataset["fax_location"],
Subject = dataset["subject"]
};
}
}
但是,当涉及到使用 Moq 框架进行单元模拟测试时,我不知道如何编写 Moq Setup,它在以下代码中返回:
public class JohnDoeClassTests
{
[Fact]
public void MaryDoeMethodTest_Valid()
{
Mock<ITargetWrapper<dynamic>> targetWrapperMock = new Mock<ITargetWrapper<dynamic>>();
dynamic returnedInfo = new ExpandoObject();
returnedInfo.Id = 3;
returnedInfo.fax_id = 7;
returnedInfo.fax_number = “416-949-9393”;
returnedInfo.fax_location =”348 Rover Drive, New York, NY, USA”;
returnedInfo.Subject = “Tax Rebate info 2023”;
graphQLResponseWrapperMock.Setup(r => r.Data …What toplace as code here in order Setup someDynamicMetaDataEntity dynamic property to return > something ?
.Returns(What do I place here in order to return the returnedInfo dynamic object );
}
}
有人可以提供 Moq 的设置代码,它是关于模拟有问题的动态属性的 Return 吗?
大多数时候动态是由一个值支撑的,并且只允许动态访问。鉴于您将数据作为键/值结构访问,您可以模拟字典
Mock<ITargetWrapper<dynamic>> targetWrapperMock = new Mock<ITargetWrapper<dynamic>>();
Dictionary<string, object> dictionary = new Dictionary<string, object>
{
["Id"] = 3;
...
}
targetWrapperMock
.Setup(r => r.Data)
.Returns(dictionary);
首先你的
MaryDoeMethod
不会工作。它会抛出RuntimeBinderException
:
无法将索引应用于“System.Dynamic.ExpandoObject”类型的表达式
为了解决索引问题你需要明确声明
ExpandoObject
应该被视为IDictionary<string, object>
IDictionary<string, object> dataset = targetWrapper.Data.someDynamicMetaDataEntity;
现在,回到你的测试。我建议使用
anonymous type
构造预期的返回对象,然后使用 some helper method 将其转换为 dynamic
.
辅助方法
public ExpandoObject ToExpandoObject(object obj)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(obj.GetType()))
{
expando.Add(property.Name, property.GetValue(obj));
}
return (ExpandoObject)expando;
}
这不适用于嵌套数据结构。您要么需要扩展它以与它们一起工作,要么手动创建外部
ExpandoObject
。为了简单起见,让我向您展示后一个:
var expected = new
{
someDynamicMetaDataEntity = new
{
id = 3,
fax_id = 7,
fax_number = "416 - 949 - 9393",
fax_location = "348 Rover Drive, New York, NY, USA",
subject = "Tax Rebate info 2023",
}
};
IDictionary<string, object> expando = new ExpandoObject();
expando.Add(nameof(expected.someDynamicMetaDataEntity), ToExpandoObject(expected.someDynamicMetaDataEntity));
有了它,模拟设置就这么简单
targetWrapperMock.Setup(w => w.Data).Returns(expando);
在这里您可以找到关于 dotnet fiddle 的工作示例:https://dotnetfiddle.net/vWC5VA