Частичное издевательство над внутренним методом класса с помощью Moq

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

Рассмотрим следующий класс и тестовый файл:

public class ClassUnderTest
{
    public string NotMockedPublicMethod()
    {
        return MockedMethod();
    }

    virtual public string MockedMethod()
    {
        return "original";
    }
}

Следующий тестовый пример будет работать:

var mock = new Mock<ClassUnderTest> { CallBase = true };
mock.Setup(m => m.MockedMethod()).Returns("mocked");

Assert.AreEqual("mocked", mock.Object.NotMockedPublicMethod());

Но скажем, этот мой MockedMethod() не имеет никакой внешней полезности. Проблема в том, что пометка этого метода как internal (даже при правильном использовании InternalsVisibleTo()):

virtual internal string MockedMethod()

сделает точно такой же тест неудачным с сообщением Assert.AreEqual failed. Expected:<mocked>. Actual:<original>.

Это ошибка Moq или какое-то ограничение?


person Caio Cunha    schedule 04.01.2014    source источник
comment
Проверьте этот пост: stackoverflow.com /вопросы/1458300/   -  person Blindsniper    schedule 04.01.2014
comment
Спасибо @Blindsniper, но моя проблема не в том, чтобы просто издеваться над методом internal. Как я уже сказал, я использовал директиву InternalsVisibleTo, но по какой-то причине тест перестал выполняться после изменения ее на внутреннюю.   -  person Caio Cunha    schedule 04.01.2014
comment
Похоже, это должно сработать. Вы не получаете никаких исключений от Moq по поводу насмешек над недоступным участником? Тогда Setup должен работать. Что произойдет, если вы не установите CallBase = true?   -  person Jeppe Stig Nielsen    schedule 04.01.2014
comment
Спасибо @JeppeStigNielsen. Проблема была решена. Когда я сказал, что использовал InternalsVisibleTo, я не знал, что я также должен сделать его видимым для прокси-сборки. Теперь это работает.   -  person Caio Cunha    schedule 05.01.2014


Ответы (1)


Это не ошибка или ограничение. Ваш тест терпит неудачу после того, как метод стал внутренним (даже после добавления InternalsVisibleTo), потому что он не вызывает издевательский метод, а вызывает фактический метод.

Вам необходимо добавить InternalsVisibleTo для DynamicProxyGenAssembly2, а также в соответствии с приведенным ниже URL-адресом.

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

http://www.blackwasp.co.uk/MoqInternals.aspx

URL-адрес не дает правильного объяснения, но вот оно:

Moq использует DynamicProxy проекта Castle для создания прокси-серверов "на лету" во время выполнения, чтобы члены объекта могли быть перехвачены без изменения кода класса. Вот как Moq возвращает значение, указанное в "Setup().Returns" (строка "издевается" в вашем случае)

URL-адрес динамического прокси-сервера: http://www.castleproject.org/projects/dynamicproxy/

Я просмотрел исходный код (см. URL-адрес ниже) для DynamicProxy и вижу, что он использует «DynamicProxyGenAssembly2» в качестве имени сборки для сгенерированной сборки, и поэтому вам также необходимо добавить InternalsVisibleTo для DynamicProxyGenAssembly2.

public static readonly String DEFAULT_ASSEMBLY_NAME = "DynamicProxyGenAssembly2";

https://github.com/castleproject/Castle.DynamicProxy-READONLY/blob/ed8663b23a54bed641e5f97e39a6bc16fe0d976f/src/Castle.DynamicProxy/ModuleScope.cs

person Adarsh Shah    schedule 04.01.2014
comment
Идеальный! Я думал, что должен сделать его видимым только для тестовой сборки, но ваше объяснение меня просветило! Теперь ясно. Спасибо. - person Caio Cunha; 05.01.2014