Как макетировать строки в плагине Excel VSTO? - PullRequest
0 голосов
/ 25 мая 2018

Я пытаюсь поместить макет 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);
}

MockUtils

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

public static Range MergeRanges(params Range[] ranges)
{
    var range = new Moq.Mock<Range>();
    for (int i = 0; i < ranges.Length; i++)
    {
        range.SetupGet(r => r[i + 1, Moq.It.IsAny<Object>()]).Returns(ranges[i]);
    }

    range.SetupGet(r => r.Count).Returns(ranges.Length);
    range.Setup(r => r.GetEnumerator()).Returns(ranges.GetEnumerator());

    return range.Object;
}

1 Ответ

0 голосов
/ 02 июня 2018

Индексатор Range возвращает динамический объект, это источник вашей проблемы.

enter image description here

Moq использует Castle Dynamic proxy для генерации поддельных объектов, Castle.Proxies.RangeProxy - это сгенерированный класс в вашем случае.Так как этот объект не является COM объектом, вызывается обработка тех, что связыватель времени выполнения C #.Связыватель времени выполнения разрешает тип и ищет метод индексатора, но ему не удалось разрешить его, потому что у сгенерированного класса его нет.

Самый простой способ решить ваш вопрос - вернуть результат индексатора в строгийRange локальная переменная:

enter image description here

Тогда ваш тест не пройден, поскольку 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 раз с момента его написания ... Итак, позвольте компилятору удалить транзитивные локальные переменные и сделать его дружественным для отладки кодом ..).

Здесь выможете прочитать простое и краткое объяснение со ссылками на то, как динамически работает в c #.

Здесь вы можете прочитать больше о Castle Dynamic Proxy.

BTW;Вы также можете сделать:

Range x = range.Rows[1].Cells;
var str = x[1].Value2;

, чтобы получить значение

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...