Moq 设置的 C# 代码及其关于模拟动态属性的返回

问题描述 投票:0回答:2

这里是关于我们的技术开发环境的信息:

  • .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 吗?

c# dynamic moq xunit expandoobject
2个回答
1
投票

大多数时候动态是由一个值支撑的,并且只允许动态访问。鉴于您将数据作为键/值结构访问,您可以模拟字典

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);

0
投票

首先你的

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

© www.soinside.com 2019 - 2024. All rights reserved.