Mock не виртуального метода чужого класса

258
09 марта 2018, 12:41

Не могу протестировать метод из за того что класс Row является составной частью чужой библиотеки.

Внутри тестируемого метода вызывается не виртуальный метод Remove() объекта класса Row.

Я пытался его "замокать":

var mockRow = new Mock<Row>();
mockRow.Setup( r => r.Remove() );
Row normalRow = mockRow.Object;

Но получаю ошибку:

System.NotSupportedException : 
Invalid setup on a non-virtual (overridable in VB) member: r => r.Remove()

Если бы я вызывал только метод Remove() объекта Row я бы мог создать интерфейс IRow с сигнатурой void Remove() внутри и создавал бы объекты Row используя этот интерфейс. Но в других ветках алгоритма я у объекта Row вызываю разные родные его методы, а писать все возможные вызовы этого объекта я думаю не самая элегантная идея.

Есть ли способ как то решить проблему?

На всякий случай привожу часть метода который тестирую:

public virtual bool Delete( string[] idArray )
{
    WorksheetPart worksheetPart = _rwh.GetWorksheetPart();
    IEnumerable<Row> rows = _rwh.GetRows( worksheetPart );
    List<string> deletedRowsId = new List<string>();
    bool setOffsetIndexesRow = false;
    if ( rows != null && idArray != null )
    {
        foreach ( string idDeleteRow in idArray )
        {
            foreach ( Row row in rows )
            {
                if ( setOffsetIndexesRow )
                {
                    SetOffsetInRowsAndCells( row );
                }
                if ( _rwh.IdCompare( idDeleteRow, row ) )
                {
                    row.Remove(); // <---------------------------
                    setOffsetIndexesRow = true;
                    deletedRowsId.Add( idDeleteRow );
                }
            }
            setOffsetIndexesRow = false;
        }
    } else {
        //....
    }
//.....
}

Так же код теста(может я делаю что-то не так):

[Fact]
public void Delete_Return_True_When_Deleted_Row_Equal_Recived_Ids()
{
    var mockRow = new Mock<Row>();
    mockRow.Setup( r => r.Remove() );
    Row normalRow = mockRow.Object;
    IEnumerable<Row> rowlist = new List<Row>( new Row[] { normalRow } );
    var mockRowWriterHelper = Mock.Of<RoWriterHandler>(
        rwh => rwh.GetRows( It.IsAny<WorksheetPart>() ) == rowlist &&
                rwh.IdCompare( It.IsAny<string>(), It.IsAny<Row>() ) == true
        );
    var rowDeleter = new RowDeleter( string.Empty, string.Empty, null, mockRowWriterHelper );
    string[] idArray = new string[] { "test" };
    //
    var resultStatus = rowDeleter.Delete( idArray );
    //
    Assert.True( resultStatus );
}
Answer 1

Я думаю, что в юнит текстах нет смысла тестить чужой код. Если вам надо как то переварить из Row во что то с виртуальными методами, закрывайте чужой код интерфейсом и пишите декоратор/адаптер, мокайте интерфейс

public class Row
{
    public void Remove()
    {       
    }
}
public interface IRow
{
    void Remove();
}
public class RowAdapter : IRow
{
    private Row _inner;
    public RowAdapter (Row inner)
    {
        _inner = inner;
    }
    public virtual void Remove()
    {
        _inner.Remove();
    }
}
READ ALSO
Создание колоды из двух Enum

Создание колоды из двух Enum

Я хочу создать колоду карт используя два Enum

209
nbitcoin получение баланса

nbitcoin получение баланса

Пытаюсь получить баланс :

194
Как достать из enum число и присвоить его другой переменной?

Как достать из enum число и присвоить его другой переменной?

Как достать из enum число и присвоить это число другой переменной ? Учитывая что элемент enum будет выбираться программой рандомным образом

187