Утверждение, что метод вызывается ровно один раз
Я хочу сказать, что метод вызывается ровно один раз. Я использую 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()
.
Ответы
Ответ 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 перехватит первый вызов, а остальные будут переданы исходному методу. Так что это отстой, но это правда.
Вам нужно будет создать ручной макет. Выведите "проверяемый" класс и дайте ему возможность поднять после первого вызова.