Moq - mock.Object.MyMethod насмешка не работает - PullRequest
2 голосов
/ 21 марта 2012

У меня странная проблема. Я не слишком знаком с Moq, потому что я больше знаком с GUI. Я пытался смоделировать фабричный метод в моем коде. Фабрика выглядит следующим образом и возвращает экземпляр ISettings, который выполняет много операций ввода-вывода. Я хочу, чтобы он возвращал только экземпляр ISettings из памяти, чтобы ускорить мой тест.

public class SettingsFactory
{
    internal ISettings mSettingsImpl;
    internal virtual ISettings CreateOrGetSettings()
    {
        return mSettingsImpl ?? (mSettingsImpl = new XmlSettings());
    }
}

и макет

var imocked = new Mock<SettingsFactory>() {CallBase = false};
imocked.Setup(x => x.CreateOrGetSettings()).Returns(new NonPersistingSettings());
var tryToSeeTheType = imocked.Object.CreateOrGetSettings();

tryToSeeTheType, однако, является XMLSettings, а не NonPersistingSettings, как я ожидал. Последовательность результатов в коде показала мне, что он идет прямо в оригинальный метод фабрики. Любые предложения, что я делаю не так здесь?

1 Ответ

0 голосов
/ 25 апреля 2012

Свойство «Объект» для смоделированного объекта на самом деле не является экземпляром класса, который вы пытаетесь смоделировать.

Цель макета - иметь возможность заменить объект, от которого зависит метод, который вы пытаетесь проверить.

Представьте, что ваш SettingsFactory выполняет очень дорогие операции, такие как, например, доступ к сети, базе данных или файловой системе. Вы не хотите, чтобы ваш тест имел доступ к этим дорогим ресурсам, поэтому вы создаете макет. Я был бы что-то вроде этого:

public class ClassThatUsesSettingsFactory
{
    private readonly SettingsFactory _settingsFactory;

    public ClassThatUsesSettingsFactory(SettingsFactory settingsFactory)
    {
       _settingsFactory = settingsFactory;
    }

    public void MethodThatCallsSettingsFactory()
    {
       //... do something
       var settings = _settingsFactory.CreateOrGetSettings();
       //... do something
    }
}

Таким образом, вы можете заменить SettingsFactory на макет вашего юнит-теста следующим образом:

[TestMethod]
public void MakeSureSettingsFactoryIsCalled()
{
   var settingsFactoryMock = new Mock<SettingsFactory>();

   settingsFactoryMock.Setup(f => f.CreateOrGetSettings(), Times.Once).Verifiable();

   var subjectUnderTest = new ClassThatUsesSettingsFactory(settingsFactoryMock.Object);

   subjectUnderTest.MethodThatCallsSettingsFactory();

   settingsFactoryMock.Verify();
}

Этот модульный тест в основном только проверяет, что метод CreateOrGetSettings вызывается один раз и только один раз, когда выполняется MethodThatCallsSettingsFactory.

Что делает Moq, так это создает другой класс с другой реализацией своего виртуального метода, который, скорее всего, установит флаг в true после его вызова, а затем проверит значение этого флага в методе «Проверка».

Здесь есть что понять, поэтому я надеюсь, что это достаточно ясно, поскольку вы упомянули, что у вас нет большого опыта работы с Moq.

...