Подтвердить что ты не робот

Утверждение, что метод вызывается ровно один раз

Я хочу сказать, что метод вызывается ровно один раз. Я использую 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().

4b9b3361

Ответ 1

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

[Test]
public void just_once()
{
    // Arrange
    var a = MockRepository.GenerateMock<ISomeDataSource>();
    a.Expect(x => x.GetSomethingThatTakesALotOfResources()).Return(new Something()).Repeat.Once();
    a.Stub(x => x.GetSomethingThatTakesALotOfResources()).Throw(new InvalidOperationException("gotcha"));

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

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

    // Assert
    a.VerifyAllExpectations();
}

Ответ 2

Я использую расширение 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();
    }

Ответ 3

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

Разница между окурками и mocks

...

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

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

ВАЖНО: заглушка никогда не вызовет test to fail.

Ответ 4

Вот что я только что сделал (как рекомендовано Ray Houston). Я по-прежнему ценю более элегантное решение...

[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);
}

Ответ 5

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

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

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

Ответ 6

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

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

helloworld.Process()

mock.VerifyAllExpectations();

Ответ 7

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

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

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

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