You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单元测试:Mock数据仅首次返回有效值,后续返回null的问题求助

单元测试SolidEdge API时Mock数据仅首次调用有效问题解决

问题描述

我正在对与SolidEdge API(一款类似AutoCAD的COM组件,用于实现3D模型修改自动化)交互的方法进行单元测试。当前遇到的问题是:Mock数据仅能返回一次,后续调用会返回null。所有Mock配置在首次调用时正常工作,但第二次调用同一属性时就会失效。例如,从includeIn1中获取到值“Yes”,但从includeIn2中得到的却是null,尽管两者访问的是同一个属性。

相关代码

public static ResultModel GetMockedAssemblyDocument(MockRequestModel mockRequestModel)
{
    var mockAssemblyDocument = new Mock<AssemblyDocument>();
    var mockOccurrences = new Mock<Occurrences>();
    var mockOccurrenceList = new List<Mock<Occurrence>>();

    foreach (var occurrence in mockRequestModel.OccurrencesDetails)
    {
        var mockOccurrence = MockSolidEdgeDocumentOccurrence(occurrence.OccurrenceName, occurrence.Properties, occurrence.Variables);
        mockOccurrenceList.Add(mockOccurrence);
    }

    mockOccurrences.Setup(o => o.GetEnumerator()).Returns(mockOccurrenceList.Select(mock => mock.Object).GetEnumerator());
    mockAssemblyDocument.Setup(doc => doc.Occurrences).Returns(mockOccurrences.Object);

    return new ResultModel { MockedAssemblyDocument = mockAssemblyDocument, MockedAssemblyDocumentCount = 2 };
}

public static Mock<Occurrence> MockSolidEdgeDocumentOccurrence(string occurrenceName, Dictionary<string, object> properties,
    Dictionary<string, VariableInfo> variables)
{
   // Existing code
    mockOccurrence1.SetupGet(o => o.OccurrenceDocument).Returns(() =>
    {
        var mockSolidEdgeDocument = new Mock<SolidEdgeDocument>();

        var mockPropertySets = GetPropertySetsMock(properties);
        mockSolidEdgeDocument.Setup(doc => doc.Properties).Returns(mockPropertySets.Object);

        return mockSolidEdgeDocument.Object;
    });

    return mockOccurrence1;
}

private static Mock<PropertySets> GetPropertySetsMock(Dictionary<string, object> properties)
{
    var mockPropertySets = new Mock<PropertySets>();
    var mockPropertySet = new Mock<Properties>();

    var propertyObjectType = new List<dynamic>();
    foreach (var property in properties)
    {
        dynamic dynamicProperty = new ExpandoObject();
        dynamicProperty.Name = property.Key;
        dynamicProperty.Value = property.Value;

        propertyObjectType.Add(dynamicProperty);
    }
    mockPropertySet.Setup(ps => ps.GetEnumerator()).Returns(propertyObjectType.GetEnumerator());
    mockPropertySets.Setup(ps => ps.GetEnumerator()).Returns(new List<Properties> { mockPropertySet.Object }.GetEnumerator());

    return mockPropertySets;
}

[Test]
public void GetSupportData_ShouldReturnListOfComponents()
{
    // Arrange
    var mockRequestModel = new MockRequestModel
    {
        OccurrencesDetails = new List<MockOccurrenceRequestModel>
        {
            new()
            {
                OccurrenceName = "Occurrence1",                  
                Properties = new  Dictionary<string, object>()
                {
                    { nameof(FilePropertyNameConstants.ObjectType), nameof(ObjectTypeConstants.Elbow) },
                    { nameof(FilePropertyNameConstants.IncludeIn), "Yes" }
                }
            }
            
        }
    };

    var mockAssemblyDocument = GetMockedAssemblyDocument(mockRequestModel);
    _mockConnectionRepository.Setup(repo => repo.GetAssemblyDocument()).Returns(mockAssemblyDocument.MockedAssemblyDocument.Object);

    // Act
    var result = _isometricRepository.GetData();

    // Assert
    Assert.That(result, Is.Not.Null);      
}

public List<ResultModel> GetData()
{
    // Existing code 
    
        SolidEdgeDocument occurrenceDocument = occurrence.OccurrenceDocument;

        if (!occurrenceDocument.PropertyValueExists(FilePropertyNameConstants.IncludeIn, out object? includeIn1)) continue;
        if (!occurrenceDocument.PropertyValueExists(FilePropertyNameConstants.IncludeIn, out object? includeIn2)) continue;

        // Existing code 
    
}

问题原因

核心问题在于枚举器只能被遍历一次:

  1. 在GetPropertySetsMock方法中,直接返回了预先创建好的枚举器实例。当第一次调用PropertyValueExists时,枚举器已经被遍历到末尾,第二次调用时没有数据可以返回,导致获取属性值失败。
  2. 同理,mockOccurrences的GetEnumerator设置也存在同样问题,多次遍历Occurrences会出现失效情况。

解决方案

修改所有GetEnumerator的Setup逻辑,使用延迟创建枚举器的方式,每次调用GetEnumerator都返回一个新的实例:

1. 修改GetPropertySetsMock方法

private static Mock<PropertySets> GetPropertySetsMock(Dictionary<string, object> properties)
{
    var mockPropertySets = new Mock<PropertySets>();
    var mockPropertySet = new Mock<Properties>();

    var propertyObjectType = new List<dynamic>();
    foreach (var property in properties)
    {
        dynamic dynamicProperty = new ExpandoObject();
        dynamicProperty.Name = property.Key;
        dynamicProperty.Value = property.Value;

        propertyObjectType.Add(dynamicProperty);
    }
    // 延迟返回新的枚举器
    mockPropertySet.Setup(ps => ps.GetEnumerator()).Returns(() => propertyObjectType.GetEnumerator());
    // 同样延迟返回新的枚举器
    mockPropertySets.Setup(ps => ps.GetEnumerator()).Returns(() => new List<Properties> { mockPropertySet.Object }.GetEnumerator());

    return mockPropertySets;
}

2. 修改GetMockedAssemblyDocument中Occurrences的枚举器设置

// 延迟返回新的枚举器
mockOccurrences.Setup(o => o.GetEnumerator()).Returns(() => mockOccurrenceList.Select(mock => mock.Object).GetEnumerator());

原理说明

使用Returns(() => ...)的Lambda表达式,每次调用GetEnumerator方法时都会执行Lambda逻辑,创建并返回一个全新的枚举器实例,这样每次遍历都能从头开始获取数据,避免了枚举器耗尽导致的返回null问题。

内容的提问来源于stack exchange,提问作者prisan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 20:35:13