Moq - вызов двух функций в одном классе, один реальный, один насмешливый - PullRequest
2 голосов
/ 18 января 2012

У меня есть кусок кода, который я не могу изменить. В идеале я бы переместил метод Publish в другой класс. Насмешка станет тривиальной операцией, и я буду в порядке. Вот упрощенный пример.

public class Entity
{
  private IController _controller;

  // Omitted: Constructor where IController is assigned

  public virtual int Process()
  {
    return Publish(_controller.DoSomeStuff());
  }

  public virtual int Publish(int val)
  {
    Console.WriteLine(val);  // This is actually a call to an external system.
    return val;
  }
}

То, что я хочу сделать, это вызвать реальный Процесс метод и поддельный Публикация метод. Значение _controller также будет проверено.

Я пытался использовать moq и делал:

var mock = new Mock<IController>();
mock.Setup(m => m.DoSomeStuff()).Returns(11);

var mock2 = new Mock<Entity_Accessor>();
mock2.CallBase = true;
mock2.Setup(a => a.Publish(It.IsAny<int>())).Returns(999);
mock2.Object._controller = mock.Object;

int result = mock2.Object.Process();
Assert.AreEqual(999, result);

Когда я запускаю этот тест, вместо 999 возвращается значение 11. Если я удаляю mock2.CallBase = true, весь класс будет mocked, который возвращает значения по умолчанию для каждой функции.

Возможно ли в этом случае просто смоделировать метод Publish, сохранив первоначальную реализацию Process?

Можно ли достичь вышеизложенного с помощью другой среды для насмешек, отличной от Typemock или Justmock (не уверен, что клиент заплатит за несколько копий насмешливого инструмента)?

Спасибо!

Ответы [ 2 ]

5 голосов
/ 18 января 2012

Если вы пытаетесь протестировать функциональность метода Process, вам не следует использовать макет, вы должны использовать реальный экземпляр класса и насмехаться над интерфейсом IController и макетом DoSomeStuff для возврата ожидаемое значение, а затем убедитесь, что Process правильно обрабатывает это значение.

Если вы просто пытаетесь издеваться над своим Entity классом, тогда не нужно издеваться над IController. Просто высмеивайте ваши методы в классе Entity и пусть они возвращают то, что вы хотите.

Обновление:

Вам не нужно издеваться над частью класса, который вы тестируете. Может быть, вы должны передать ссылку на внешнюю систему, чтобы вы могли посмеяться над ней. Если код в Publish не является ответственной стороной за прямой вызов внешней системы. Это был бы рекомендуемый подход. Однако, если метод Publish отвечает за непосредственный вызов внешней системы , вам нужно использовать другой подход и вместо этого провести интеграционное тестирование.

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

2 голосов
/ 19 января 2012

Так как вы не упомянули, что ваш класс запечатан (и из-за наличия виртуальных методов я предполагаю, что это не так), вы должны рассмотреть возможность создания тестируемой версии этого для этого конкретного сценария (насмешка одной части, оставляя другую нетронутой):

public class TestableEntity : Entity
{
    internal int PublishReturnValue { get; set; }

    public override int Publish(int value)
    {
        return PublishReturnValue;
    }
}

Таким образом, вы все еще можете проверять метод Process обычным способом, но вы можете в некотором роде mock другой:

var controllerMock = new Mock<IController>();
controllerMock.Setup(m => m.DoSomeStuff()).Returns(11);
// assuming appropriate ctors
var testableEntity = new TestableEntity(controllerMock);
testableEntity.PublishReturnValue = 999;

var result = testableEntity.Process();

Assert.AreEqual(999, result);        

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

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