How to test for exceptions thrown using xUnit, SubSpec and FakeItEasy

bdd, c#, fakeiteasy, unit-testing, xunit

Solution

I would do it like this:

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

Or better still, switching SubSpec for xBehave.net and introducing 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());

Problem

I’m using xUnit, SubSpec and FakeItEasy for my unit tests. I’ve so far created some positive unit tests like the following: ``` "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)); ``` But now I want to write some negative unit tests and check that certain methods don't get called, and an exception is thrown 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 ); ``` I can see FakeItEasy has a MustNotHaveHappened extension method, and xUnit has an Assert.Throws method. But how do I put it all together? The exception I want to test for should occur when the Save method is called. So I’m guessing I should wrap an Assert.Throws method around the presenter.Save() method call, but I thought the presenter.Save method should be called in the .Do(() => ... Can you please advise if my unit test should look like below or something else? ``` "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()); ``` Many thanks

Original source