Rhino Mock и Mock в целом - PullRequest
3 голосов
/ 04 марта 2009

Есть ли какое-либо место или кто-нибудь, кто мог бы объяснить, как это работает на простом английском языке вместо " определения терминов в терминах самих себя "?

Ответы [ 4 ]

9 голосов
/ 04 марта 2009

Итак, у вас есть класс, который зависит от чего-то еще.

Позволяет использовать метафору: автомобиль требует двигателя.

Автомобиль зависит от двигателя. Легко проверить, что автомобиль и двигатель работают вместе, но как насчет тестирования автомобиля без двигателя или того, что автомобиль правильно «вызывает» двигатель. То, что мы могли бы сделать, это поставить что-то (макет) на место двигателя, нажать газ (сделать вызов) и убедиться, что фальшивый (макет) двигатель получил правильный ввод в корпус дросселя. Вместо того, чтобы проверять всю систему, вы только что проверили то, что хотите, в изоляции, измеряя с помощью фиктивного объекта.

На практике все становится намного сложнее и мощнее, но ...

3 голосов
/ 04 марта 2009

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

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

Моделирующие среды как Rhino Mock помогают вам создавать фиктивные объекты, которые реагируют так, как вы ожидаете, фактический сервис. Вы можете сравнить записи с реальными ответами на сервисные вызовы, которые вы можете воспроизводить каждый раз при выполнении теста.

2 голосов
/ 20 ноября 2012

Чтобы по-настоящему понять Моксы, сначала нужно понять четыре понятия

Что такое тестирование взаимодействия

Что такое каркасы изоляции (например, издевательства над носорогом)

Что такое подделка

Что такое заглушка

И, наконец, что такое издевательство

Тестирование взаимодействия заключается в проверке, вызывает ли определенный метод (тот, который вы тестируете), другой метод в другом классе (внешняя зависимость) с параметрами, которые он должен использовать. Представьте, что у вас есть метод в некотором классе, который регистрирует каждый раз, когда он вызывается с недопустимыми параметрами. Чтобы прояснить разницу между заглушками и макетами, я добавил 2 внешних зависимости (IStringAnalyzer и ILooger):

class SomeClass
{
    IStringAnalyzer stringAnalizer;
    ILogger logger;

    public SomeClass(IStringAnalyzer stringAnalyzer, ILogger logger)
    {   
        this.logger = logger;
        this.stringAnalyzer = stringAnalyzer;
    }


    public void SomeMethod(string someParameter)
    {
        if (stringAnalyzer.IsValid(someParameter))
        {
            logger.Log("Invalid string");
        }else
        {
            //do something with someParameter
        }
    }
}

В этом примере вы хотите проверить, вызывает ли вызов метода SomeClass SomeMethod с недопустимым параметром метод журнала в ILogger со строковым параметром «Недопустимая строка». Вы не не хотите использовать ваши "настоящие" реализации IStringAnalyzer и ILogger, потому что они могут иметь ошибки, и поскольку это unit тестирование, вы просто хотите протестировать одну вещь за раз, если вы проверяете, как тестировать несколько вещей одновременно, то вы действительно делаете интеграционное тестирование. Причина, по которой тестируется только одна вещь, заключается в том, что, если ваш тест не пройден, вы сразу же знаете, что он терпит неудачу из-за единственного, что вы тестируете.

Вам нужно предоставить две альтернативные реализации, одну для IStringAnalyzer и одну для ILogger, чтобы вы могли правильно выполнить этот тест. В этих альтернативных реализациях будет разница с точки зрения того, что им нужно делать. Для IStringAnalyzer вы просто хотите, чтобы при вызове он возвращал false, чтобы тестируемый метод проходил путь кода, который вы хотите протестировать. Вы действительно не заботитесь о значении параметра (someParameter).

Для метода журнала ILogger вы хотите знать, что он был вызван и что он был вызван с помощью «неверной строки», чтобы вы могли подтвердить это в своем тесте.

Эти две альтернативные реализации IStringAnalyzer и ILogger оба называются «подделками» (потому что они подделывают внешние зависимости), но одна из них является заглушкой (IStringAnalyzer), а другая - имитатором (ILogger). Заглушка предназначена только для того, чтобы привести вас туда, куда вам нужно пойти в тесте (в этом случае метод IsValid IStringAnalyzer возвращает false). Это макет, позволяющий вам проверить, правильно ли было выполнено взаимодействие с внешней зависимостью (в данном случае ILogger). Некоторые люди называют насмешки (или насмешки такого типа) тестовым шпионом (на мой взгляд, бесконечно лучшим именем). И да, есть другие виды издевательств (хотя я никогда не использовал их). Хороший источник для этого - Работа с унаследованным кодом от Michael Feathers и Роя Ошерова «Искусство модульного тестирования».

Вы можете создать заглушку и макет "вручную", например:

class StringAnalyzerStub : IStringAnalyzer 
{   
    public bool whatToReturn;

    public StubStringAnalyzerStub(bool whatToReturn)
    {
        this.whatToReturn = whatToReturn;
    }

    public bool IsValid(string parameter)
    {
        return whatToReturn;
    }
}


class LoggerMock : ILogger
{
    public string WhatWasPassedIn;

    public void Log(string message)
    {
        WhatWasPassedIn = message;
    }
}

А вот и тест:

[Test]
public void SomeMethod_InvalidParameter_CallsLogger
{
    IStringAnalyzer s = new StringAnalyzerStub(false); //will always return false when IsValid is called
    ILogger l = new LoggerMock();
    SomeClass someClass = new SomeClass(s, l);

    someClass.SomeMethod("What you put here doesnt really matter because the stub will always return false");

    Assert.AreEqual(l.WhatWasPassedIn, "Invalid string");
}

Смысл выполнения этого вручную состоит в том, что он подвержен ошибкам и сложен в обслуживании, поэтому необходима изоляция сред, таких как Rhino Mocks. Они позволяют динамически создавать эти макеты и заглушки. Вот как будет выглядеть тот же тест с использованием Rhino Mocks (с использованием синтаксиса упорядочения, действия, утверждения):

[Test]
public void SomeMethod_InvalidParameter_CallsLogger
{
    Rhino.Mocks.MockRepository mockRepository = new Rhino.Mocks.MockRepository();
    IStringAnalyzer s = mockRepository.Stub<IStringRepository>();
    s.Expect(s => s.IsValid("something, doesnt matter").IgnoreParameters().Return(false);
    ILogger l = mockRepository.DynamicMock<ILogger>();
    l.Log("Invalid string");
    SomeClass someClass = new SomeClass(s, l);
    mockRepository.ReplayAll();

    someClass.SomeMethod("What you put here doesnt really matter because the stub will always return false");

    l.AssertWasCalled(l => l.Log("Invalid string"));
}

Термины не определены сами по себе:)

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

1 голос
/ 04 марта 2009

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

В отличие от заглушек, макеты отслеживают фактическое использование, поэтому ваш тест может проверить, что макет использовался как ожидалось.

Подробнее в статье Фаулера здесь .

...