Как протестировать исключения, созданные с помощью xUnit, SubSpec и FakeItEasy
Im, используя xUnit, SubSpec и FakeItEasy для моих модульных тестов.
Ive пока создал некоторые положительные модульные тесты, например:
"Given a Options presenter"
.Context(() =>
presenter = new OptionsPresenter(view,
A<IOptionsModel>.Ignored,
service));
"with the Initialize method called to retrieve the option values"
.Do(() =>
presenter.Initialize());
"expect the view not to be null"
.Observation(() =>
Assert.NotNull(view));
"expect the view AutoSave property to be true"
.Observation(() => Assert.True(view.AutoSave));
Но теперь я хочу написать некоторые отрицательные модульные тесты и проверить, что некоторые методы не вызываются, а исключение выбрано
например.
"Given a Options presenter"
.Context(() =>
presenter = new OptionsPresenter(view,
A<IOptionsModel>.Ignored,
service));
"with the Save method called to save the option values"
.Do(() =>
presenter.Save());
"expect an ValidationException to be thrown"
.Observation(() =>
// TODO
);
"expect an service.SaveOptions method not to be called"
.Observation(() =>
// TODO
);
Я вижу, что FakeItEasy имеет метод расширения MustNotHaveHappened, а xUnit имеет метод Assert.Throws.
Но как мне собрать все это вместе?
Исключение, которое я хочу проверить, должно возникать при вызове метода Save. Поэтому я предполагаю, что я должен обернуть метод Assert.Throws вокруг вызова метода presenter.Save(), но я подумал, что метод presenter.Save должен быть вызван в .Do(() = > ...
Не могли бы вы сообщить, должен ли мой unit test выглядеть ниже или что-то еще?
"Given a Options presenter"
.Context(() =>
presenter = new OptionsPresenter(view,
model,
service));
"expect the Presenter.Save call to throw an Exception"
.Observation(() =>
Assert.Throws<FluentValidation.ValidationException>(() => presenter.Save()));
"expect the Service.SaveOptions method not to be called"
.Observation(() =>
A.CallTo(() => service.SaveOptions(A<IOptionsModel>.Ignored)).MustNotHaveHappened());
Большое спасибо
Ответы
Ответ 1
Я бы сделал это следующим образом:
"Given a Options presenter"
.Context(() =>
presenter = new OptionsPresenter(view,
(IOptionsModel)null,
service));
"with the Save method called to save the option values"
.Do(() =>
exception = Record.Exception(() => presenter.Save()));
"expect an ValidationException to be thrown"
.Observation(() =>
Assert.IsType<ValidationException>(exception)
);
"expect an service.SaveOptions method not to be called"
.Observation(() =>
A.CallTo(() => service.SaveOptions(A<IOptionsModel>.Ignored)).MustNotHaveHappened()
);
Или еще лучше переключить SubSpec на xBehave.net и ввести FluentAssertions: -
"Given an options presenter"
.x(() => presenter = new OptionsPresenter(view, (IOptionsModel)null, service));
"When saving the options presenter"
.x(() => exception = Record.Exception(() => presenter.Save()));
"Then a validation exception is thrown"
.x(() => exception.Should().BeOfType<ValiationException>());
"And the options model must not be saved"
.x(() => A.CallTo(() =>
service.SaveOptions(A<IOptionsModel>.Ignored)).MustNotHaveHappened());
Ответ 2
Я не слышал о fakeItEasy или subSpec (тесты вы выглядите довольно напуганными, поэтому я могу проверить их:)). Однако я использую xUnit, поэтому это может быть полезно:
Я использую Record.Exception с Assert.ThrowsDelegate
Так что-то вроде:
[Fact]
public void Test()
{
// Arange
// Act
Exception ex = Record.Exception(new Assert.ThrowsDelegate(() => { service.DoStuff(); }));
// Assert
Assert.IsType(typeof(<whatever exception type you are looking for>), ex);
Assert.Equal("<whatever message text you are looking for>", ex.Message);
}
Надеюсь, что это поможет.
Ответ 3
Это один из способов сделать это в FakeItEasy.
Action act = () => someObject.SomeMethod(someArgument);
act.ShouldThrow<Exception>();