Как проверить наличие исключений с помощью xUnit, SubSpec и FakeItEasy

Я использую xUnit, SubSpec и FakeItEasy для модульных тестов. На данный момент я создал несколько положительных модульных тестов, таких как следующие:

"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));

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

e.g.

"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(() => ...

Не могли бы вы посоветовать, должен ли мой модульный тест выглядеть так, как показано ниже, или как-то иначе?

"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());

Большое спасибо


person m_collard    schedule 13.06.2012    source источник
comment
Не уверен, что это может помочь, но проверяли ли вы документацию по SubSpec, например bitbucket.org/johannesrudolph/subspec/src/a35fcc8ae1f6/test/ Также это тесты на основе BDD/спецификации, а не модульные тесты. Вы можете получить лучшую аудиторию, если включите тег BDD.   -  person Spock    schedule 11.12.2012


Ответы (3)


Я бы сделал это так:

"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());
person Adam Ralph    schedule 16.02.2013

Я не слышал о 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);
    }

Надеюсь, это поможет.

person Steve    schedule 19.12.2012

Это один из способов сделать это в FakeItEasy.

Action act = () => someObject.SomeMethod(someArgument);
act.ShouldThrow<Exception>();
person Shaun Luttin    schedule 01.12.2015
comment
Я получаю сообщение, что действие не содержит определения для ShouldThrow... Какую ссылку/сборку мне нужно включить? - person Emmanuel John; 13.11.2017