Могу ли я получить реальный Mock с использованием Rhino Mocks 3.6 без определения поддельных значений? - PullRequest
0 голосов
/ 27 марта 2011

Я использую Rhino Mocks 3.6.Я видел много видов кодирования.Иногда используя статический GenerateMock метод, иногда используя new MockRepository().Я не очень хорошо понимаю, что происходит или что лучше.Возможно, некоторые методы устарели, но в любом случае давайте перейдем к реальной проблеме.

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

    [TestMethod]
    public void TestingProperty()
    {
        Person repository = MockRepository.GenerateMock<Person>();
        // tell rhino.mocks when FirstName is called in the next time, it should return "Monica"
        repository.Expect(x => x.Title).Return("Monica");
        // get the mocking ready
        repository.Replay();

        repository.VerifyAllExpectations();

        // when getting repository.Title value, we should receive "Monica" defined previously in expectation
        Assert.AreEqual(repository.Title, "Monica");
    }

Я заметил, когда удаляю repository.Replay(), все продолжает работать.Какова цель воспроизведения, нужно ли это?

Требуется также VerifyAllExpectations?Что он делает внутри?

Могу ли я не печатать вручную "Моника" и иметь настоящий поддельный объект для Person?

Если это плохой код, пожалуйста, дайте мне знать ваши предложения!

Ответы [ 2 ]

5 голосов
/ 27 марта 2011

Похоже, вы не работали с более поздними фреймворками фиктивных объектов.

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

Этот старый стиль похож на менее изощренную версию заглушки Rhino.

С более новыми платформами фиктивных объектов вы прекращаете проверять состояние фиктивных объектов иначать проверять поведение.Вы делаете утверждения о том, как тестируемый код вызывает ваши фиктивные объекты, а не о том, как задаются свойства / элементы.

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

Несколько советов по исправлению этого кода:

  • Здесь используются две части API Rhino Mocks.Отбросьте часть записи / воспроизведения, так как она более запутанная, и придерживайтесь синтаксиса AAA (Arrange, Act, Assert).См. примечания к выпуску с момента добавления AAA
  • Остановите тестирование фиктивных объектов напрямую
  • Проверьте код, который использует фиктивный объект, и добавьте ожидания длякакой этот код вызовет на макете
  • Вызовите тестируемый код перед вызовом на VerifyAllExepectations, передавая ему при необходимости макеты
  • Убедитесь, что методы исвойства, которые вы хотите смоделировать, помечены virtual или abstract, или что ваш смоделирован на основе interface
  • Разделите ваши тестовые случаи на тесты, которые проверяют вызовы имитаций, и тесты, которые проверяют состояние /возвращаемые значения верны в тестируемом коде
  • Не устанавливайте состояние для макетов вообще, поскольку вы устанавливаете его напрямую, и это просто тестирует ваш тестовый пример

Вот некоторые исправленныепример кода:

public class ObjectThatUsesPerson
{
    public ObjectThatUsesPerson(Person person)
    {
        this.person = person;
    }

    public string SomeMethod()
    {
        return person.Title;
    }

    private Person person;
}

[TestMethod]
public void TestingPropertyGotCalled()
{
    // Arrange
    var mockPerson = MockRepository.GenerateMock<Person>();
    mockPerson.Expect(x => x.Title).Return("Monica");
    var someObject = new ObjectThatUsesPerson(mockPerson);

    // Act
    someObject.SomeMethod(); // This internally calls Person.Title

    // Assert
    repository.VerifyAllExpectations();
    // or: mockPerson.AssertWasCalled(x => x.Title);
}

[TestMethod]
public void TestingMethodResult()
{
    // Arrange
    var stubPerson = MockRepository.GenerateStub<Person>();
    stubPerson.Stub(x => x.Title).Return("Monica");
    var someObject = new ObjectThatUsesPerson(stubPerson);

    // Act
    string result = someObject.SomeMethod();

    // Assert
    Assert.AreEqual("Monica", result, "Expected SomeMethod to return correct value");
}

Чтобы проверить, что это работает правильно, попробуйте выполнить следующие действия (измените код после каждого):

  • Запустите его один раз и убедитесь, что он прошел
  • Удалить строку Expect, ги убедитесь, что он все еще проходит (это не строгая насмешка)
  • Добавьте дополнительную строку Expect, возвращая другое значение.Запустите его и убедитесь, что он не работает
  • Добавьте дополнительный SomeMethod вызов.Запустите его и убедитесь, что оно прошло (не строгая проверка)
  • Удалите код внутри SomeMethod.Запустите его и убедитесь, что он не работает
2 голосов
/ 27 марта 2011

Существует два распространенных подхода к написанию тестов с помощью RhinoMocks - макет объектов с ожиданиями и Arrange, Act, Assert (AAA). Вы должны прочитать http://ayende.com/Wiki/Rhino+Mocks+3.5.ashx статью, которая описывает это очень подробно.

Ответ Мерлина Моргана-Грэма охватывает первый подход. Follwing - это то, как вы можете написать тот же тест, используя модель AAA:

[TestMethod]
public void TestingPropertyUsingAAA()
{   
   // Arrange
   var mockPerson = MockRepository.GenerateStub<Person>();
   repository.Stub(x => x.Title).Return("Monica");

   // Act
   var someObject = new ObjectThatUsesPerson(mockPerson);
   someObject.SomeMethod(); // This internally calls Person.Title    

   // Assert
   repository.AssertWasCalled(x => x.Title);
}
...