如何模拟 Excel VSTO 插件中的行?

我正在尝试将一个模拟Range(包含带有值的单元格)放在一个新的Range. 但是当我尝试从 访问特定元素时Range,会引发异常。


我已经尝试了一切,有没有人知道我在这里做错了什么?


例外


消息:测试方法 xxx.MockUtilsTest.MockRowsTest 抛出异常:Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:无法将 [] 索引应用于“Castle.Proxies.RangeProxy”类型的表达式


测试


[TestMethod]

public void MockRowsTest()

{

    var row1 = MockUtils.MockCells("test_row_1", "test_row_1");

    var row2 = MockUtils.MockCells("test_row_2", "test_row_2");

    var range = MockUtils.MockRows(row1, row2);


    Assert.IsNotNull(range);

    Assert.AreEqual(2, range.Count);

    Assert.IsNotNull(range.Rows);

    Assert.AreEqual(2, range.Rows.Count);

    Assert.AreSame(row1, range.Rows[1].Cells[1]); // exception is thrown here

    Assert.AreSame(row2, range.Rows[2].Cells[1]);

    Assert.AreEqual("test_row_1", range.Rows[1].Cells[1].Value2);

    Assert.AreEqual("test_row_2", range.Rows[2].Cells[1].Value2);

}

模拟工具


public static Range MockCellValue2(Object value)

{

    var cell = new Moq.Mock<Range>();

    cell.Setup(c => c.Value2).Returns(value);


    return cell.Object;

}


public static Range MockCells(params Object[] values)

{

    var cells = new Moq.Mock<Range>();

    for (int i = 0; i < values.Length; i++)

    {

        var cell = MockCellValue2(values[i]);

        cells.SetupGet(c => c[i + 1, Moq.It.IsAny<Object>()]).Returns(cell);

    }


    var row = new Moq.Mock<Range>();

    row.SetupGet(r => r.Cells).Returns(cells.Object);

    row.SetupGet(r => r.Count).Returns(values.Length);


    return row.Object;

}


public static Range MockRows(params Range[] rows)

{

    var mergedRows = MergeRanges(rows);

    var range = new Moq.Mock<Range>();

    range.SetupGet(r => r.Count).Returns(rows.Length);

    range.SetupGet(r => r.Rows).Returns(() => mergedRows);

    range.Setup(r => r.GetEnumerator()).Returns(rows.GetEnumerator());


    return range.Object;

}

慕妹3242003
浏览 152回答 1
1回答

交互式爱情

索引器Range返回一个动态对象,这是您问题的根源。Moq 用于Castle Dynamic proxy生成假对象,Castle.Proxies.RangeProxy在您的情况下是生成的类。由于此对象不是COM对象,因此正在调用 C# 运行时绑定器的处理。运行时绑定器解析类型并寻找索引器方法,但他无法解析它,因为生成的类没有它。解决您的最简单方法是将索引器结果返回到严格的Range局部变量:那么你的测试将失败,因为range.Rows[1]它等于row1......因此,将您的测试代码更改为:[TestMethod]public void MockRowsTest(){&nbsp; &nbsp; var row1 = MockUtils.MockCells("test_row_1", "test_row_1");&nbsp; &nbsp; var row2 = MockUtils.MockCells("test_row_2", "test_row_2");&nbsp; &nbsp; var range = MockUtils.MockRows(row1, row2);&nbsp; &nbsp; Assert.IsNotNull(range);&nbsp; &nbsp; Assert.AreEqual(2, range.Count);&nbsp; &nbsp; Assert.IsNotNull(range.Rows);&nbsp; &nbsp; Assert.AreEqual(2, range.Rows.Count);&nbsp; &nbsp; Range x = range.Rows[1];&nbsp; &nbsp; Range y = range.Rows[2];&nbsp; &nbsp; var xCell = x.Cells[1];&nbsp; &nbsp; var yCell = y.Cells[1];&nbsp; &nbsp; Assert.AreSame(row1, x);&nbsp;&nbsp; &nbsp; Assert.AreSame(row2, y);&nbsp; &nbsp; Assert.AreEqual("test_row_1", xCell.Value2);&nbsp; &nbsp; Assert.AreEqual("test_row_2", yCell.Value2);}上面的UT会通过测试。IMO 你应该打破对“原子 OPS(多行)和方法”的聚合调用,而不是因为它会通过测试,因为它会使你的代码成为调试友好的代码。(我称之为“第 11 条规则”,你的代码从编写时起至少会再读 10 次......所以让编译器删除可传递的局部变量并使其成为调试友好的代码......)。顺便提一句; 你也可以这样做:Range x = range.Rows[1].Cells;var str = x[1].Value2;
打开App,查看更多内容
随时随地看视频慕课网APP