Утверждая, что метод вызывается ровно один раз - PullRequest
28 голосов
/ 13 ноября 2008

Я хочу сказать, что метод вызывается ровно один раз. Я использую RhinoMocks 3.5.

Вот то, что я думал, будет работать:

[Test]
public void just_once()
{
    var key = "id_of_something";

    var source = MockRepository.GenerateStub<ISomeDataSource>();
    source.Expect(x => x.GetSomethingThatTakesALotOfResources(key))
        .Return(new Something())
        .Repeat.Once();

    var client = new Client(soure);

    // the first call I expect the client to use the source
    client.GetMeMyThing(key);

    // the second call the result should be cached
    // and source is not used
    client.GetMeMyThing(key);
}

Я хочу, чтобы этот тест не прошел, если второй вызов GetMeMyThing() вызывает source.GetSomethingThatTakesALotOfResources().

Ответы [ 7 ]

32 голосов
/ 20 февраля 2009

Вот как я могу убедиться, что метод вызывается один раз.

[Test]
public void just_once()
{
    // Arrange (Important to GenerateMock not GenerateStub)
    var a = MockRepository.GenerateMock<ISomeDataSource>();
    a.Expect(x => x.GetSomethingThatTakesALotOfResources()).Return(new Something()).Repeat.Once();

    // Act
    // First invocation should call GetSomethingThatTakesALotOfResources
    a.GetMeMyThing();

    // Second invocation should return cached result
    a.GetMeMyThing();

    // Assert
    a.VerifyAllExpectations();
}
15 голосов
/ 20 мая 2009

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

    [Test]
    public void just_once()
    {
        var key = "id_of_something";

        var source = MockRepository.GenerateStub<ISomeDataSource>();

        // set a positive expectation
        source.Expect(x => x.GetSomethingThatTakesALotOfResources(key))
            .Return(new Something())
            .Repeat.Once();

        var client = new Client(soure);
        client.GetMeMyThing(key);
        client.GetMeMyThing(key);

        source.AssertWasCalled(x => x.GetSomethingThatTakesALotOfResources(key),
                               x => x.Repeat.Once());
        source.VerifyAllExpectations();
    }
5 голосов
/ 13 ноября 2008

Вас может заинтересовать этот бит из документации Rhino Mocks 3.5 (цитируется ниже) Похоже, вам нужно издеваться над классом, а не заглывать, чтобы он работал так, как вы ожидаете.

Разница между заглушками и макетами

...

Макет - это объект, который мы можем установить ожидания и что проверят что ожидаемые действия действительно произошло. Заглушка это объект, который вы использовать для перехода к коду под тестовое задание. Вы можете настроить ожидания на это, так что это будет действовать определенным образом, но эти ожидания никогда не будут проверено. Свойства заглушки будут автоматически ведет себя как обычно свойства, и вы не можете установить ожидания от них.

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

ВАЖНО: заглушка никогда не вызовет тест не пройден.

2 голосов
/ 04 марта 2011

Вы можете передать делегата в WhenCalled для подсчета вызовов:

...
uint callCount = 0;
source.Expect(x => x.GetSomethingThatTakesALotOfResources(key))
    .Return(new Something())
    .WhenCalled((y) => { callCount++; });
...
Assert.AreEqual(1, callCount);

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

2 голосов
/ 13 ноября 2008

Вот что я только что сделал (как рекомендовано Рэй Хьюстон ). Я бы все равно оценил более элегантное решение ...

[Test]
public void just_once()
{
    var key = "id_of_something";

    var source = MockRepository.GenerateStub<ISomeDataSource>();

    // set a positive expectation
    source.Expect(x => x.GetSomethingThatTakesALotOfResources(key))
        .Return(new Something())
        .Repeat.Once();

    var client = new Client(soure);

    client.GetMeMyThing(key);

    // set a negative expectation
    source.Expect(x => x.GetSomethingThatTakesALotOfResources(key))
        .Return(new Something())
        .Repeat.Never();

    client.GetMeMyThing(key);
}
0 голосов
/ 01 ноября 2017

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

var mock = MockRepository.GenerateStrictMock<IMustOnlyBeCalledOnce>();
mock.Expect(a => a.Process()).Repeat.Once();
var helloWorld= new HelloWorld(mock);

helloworld.Process()

mock.VerifyAllExpectations();
0 голосов
/ 21 апреля 2009

Наличие функции «Точно» было бы удобно для написания тестов для кода, который в противном случае мог бы попасть в бесконечный цикл. Я хотел бы написать тест, чтобы второй вызов метода вызвал исключение.

Некоторые библиотеки для python позволяют упорядочивать ожидания, поэтому первая возвращает false, а вторая вызывает исключение.

Носорог этого не сделает. Частичная имитация с .Once будет перехватывать первый вызов, а остальные будут передаваться исходному методу. Так что это отстой, но это правда.

Тебе придется создать макет руки. Выведите «тестируемый» класс и дайте ему возможность повышаться после первого звонка.

...