Ошибка Moq: Невозможно привести «AnObject» к «System.Delegate» - PullRequest
2 голосов
/ 14 марта 2012

Я пытался обойти эту проблему уже пару дней, но безрезультатно.Я пытаюсь проверить функциональность AnObject.AnAction (упреждающие извинения, я должен запутать имена классов / методов.) Моя цель состоит в том, чтобы MyTestObj.do_work (AnObject) фактически ничего не делал, когда он вызывается.У него есть код, который я хочу вызывать в среде модульного тестирования.

Вот мой код модульного теста:

Mock< MyTestObj > myTestObj_mock = new Mock< MyTestObj > ();
myTestObj_mock.Setup( e => e.do_work( It.IsAny< AnObject > () ) );
...
AnObject tester = new AnObject();
tester.anAction( myTestObj_mock.Object );

в методе AnObject.AnAction (MyTestObj mto):

...
mto.do_work( this );
...

Именно в этот момент при запуске я получаю эту ошибку:

System.InvalidCastException : Unable to cast object of type  
'myNamespace.AnObject' to type 'System.Delegate'.     

MyTestObj.do_work - это виртуальный метод.

Я понятия не имею, почемуэта ошибка идет вверх.Я прошел по коду, когда NUnit запустил его, и я уверен, что это тот момент, когда он падает.Это не пойдет дальше в код.

Я действительно в замешательстве.Кто-нибудь знает, что происходит?

Заранее спасибо!


*** Обновления ***

Я попытался создать экземпляр AnObject в AnObject.AnAction и передать его вместо 'this':

...
AnObject test = new AnObject();
mto.do_work( test );
...

Это не имело никакого эффекта.

Ответы [ 2 ]

3 голосов
/ 14 марта 2012

Я наконец смог добраться до компилятора и поиграть с кодом, и вот что я нашел. Это в основном то, что Джайлс сказал выше для своей первой части вопроса.

Вот подсказка кода для установки:

Определяет настройку по ложному типу для вызова метода, возвращающего значение.

И вот актуальный код для установки

public ISetup<T> Setup(Expression<Action<T>> expression)

Итак, программа установки на самом деле устанавливает код как действие (делегат, в основном). Когда запускается тестовый прогон, он достигает этой точки и обычно ожидает передачи делегата методу Returns

public IReturnsResult<TMock> Returns(TResult value)

Итак, этого никогда не делается, и вместо того, чтобы Mock пробежал весь ожидаемый путь и согласовал весь код, он возвращает неверные значения.

Ооо, это в основном то, где объяснение Джайлса является правильным. Если вы проверяете, что вызывается метод do_work, то вы хотите использовать Verify (который действительно использует ваш поддельный объект в качестве макета). Однако, если нет, то вам не нужно даже настраивать это, поскольку это ничего не делает. Если это так, то, возможно, этот фрагмент кода не должен находиться в этом конкретном блоке кода, но вам лучше это оценить.

И, наконец, метод Setup следует использовать только в том случае, если вы действительно используете свой объект в качестве заглушки, просто используя его для внедрения логики в ваш код.

Надеюсь, это имеет смысл и поможет вам решить вашу проблему.

Кроме того, Callback может пригодиться здесь в зависимости от того, что вы делаете. Но я не уверен. У них есть много примеров в Moq quickstart

ОБНОВЛЕНИЕ ДЛЯ МОЕЙ ПОПЫТКИ ПРИ ВОССТАНОВЛЕНИИ с использованием версии 4.0.10827 ... и не было проблем

    [Test]
    public void teststuff()
    {
        Mock<MyTestObj> myTestObj_mock = new Mock<MyTestObj>();
        myTestObj_mock.Setup(e => e.do_work(It.IsAny<AnObject>()));
        AnObject tester = new AnObject();
        tester.anAction(myTestObj_mock.Object);
    }

...

public class MyTestObj
{
    public virtual void do_work(AnObject o)
    {

    }
}

public class AnObject
{
    public void anAction(MyTestObj obj)
    {
        obj.do_work(new AnObject());
    }
}
3 голосов
/ 14 марта 2012

Поскольку ваш вопрос написан, вам не нужно настраивать myTestObj_mock.do_work ().

Настройка используется, чтобы сказать, когда метод X вызывается, возвращаемое значение Y. Или, альтернативно, когда вызывается метод X, возвращается исключение Z. Спросите себя, действительно ли это то, что мне нужно сделать?

Здесь вы ничего не возвращаете из метода:

mto.do_work( this );

Также здесь:

myTestObj_mock.Setup( e => e.do_work( It.IsAny< AnObject > () ) );

Вы не определяете никаких возвратов для своих настроек.

Вы должны иметь возможность предоставить макет myTestObj_mock без определения настроек в этом случае. Просто удалите строку с программой установки и снова запустите тест.

Предположение:

Если вы определили программу установки, потому что вы хотели, чтобы ваш тест удостоверился, что AnObject.AnAction действительно вызывает метод do_work, вам нужно определить метод Verify, а не программу установки, аналогично:

mock.Verify(foo => foo.Execute("ping"));

или в вашем случае что-то вроде

myTestObj_mock.Verify(m => m.do_work(It.IsAny< AnObject > ()), Times.AtLeastOnce());

Еще одно предположение:

Если вы определили макет, потому что вы передаете ссылку "this" и ожидаете, что do_work изменит некоторые параметры "this" для прохождения теста, тогда вы не должны насмехаться здесь. Помните, что макеты на самом деле не являются экземплярами ваших объектов, поэтому код, модифицирующий эту ссылку, никогда не будет вызван

...