为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

PHP
慕妹3242003 2021-06-29 18:43:08
我正在尝试将一个模拟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;}
查看完整描述

1 回答

?
交互式爱情

TA贡献1712条经验 获得超3个赞

索引器Range返回一个动态对象,这是您问题的根源。

//img1.sycdn.imooc.com//60e01da30001f48c04010103.jpg

Moq 用于Castle Dynamic proxy生成假对象,Castle.Proxies.RangeProxy在您的情况下是生成的类。由于此对象不是COM对象,因此正在调用 C# 运行时绑定器的处理。运行时绑定器解析类型并寻找索引器方法,但他无法解析它,因为生成的类没有它。

解决您的最简单方法是将索引器结果返回到严格的Range局部变量:

//img1.sycdn.imooc.com//60e01db00001e3c909320227.jpg

那么你的测试将失败,因为range.Rows[1]它等于row1......


因此,将您的测试代码更改为:


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

    Range x = range.Rows[1];

    Range y = range.Rows[2];

    var xCell = x.Cells[1];

    var yCell = y.Cells[1];

    Assert.AreSame(row1, x); 

    Assert.AreSame(row2, y);

    Assert.AreEqual("test_row_1", xCell.Value2);

    Assert.AreEqual("test_row_2", yCell.Value2);

}

上面的UT会通过测试。IMO 你应该打破对“原子 OPS(多行)和方法”的聚合调用,而不是因为它会通过测试,因为它会使你的代码成为调试友好的代码。(我称之为“第 11 条规则”,你的代码从编写时起至少会再读 10 次......所以让编译器删除可传递的局部变量并使其成为调试友好的代码......)。

顺便提一句; 你也可以这样做:


Range x = range.Rows[1].Cells;

var str = x[1].Value2;


查看完整回答
反对 回复 2021-07-03
  • 1 回答
  • 0 关注
  • 151 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信