Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 376
m_collard Avatar asked Jun 13 '12 10:06

m_collard


People also ask

How do I assert exception messages in xUnit?

xUnit uses Assert. Throws to test for exception types. You could catch the exception and Assert against the message if you needed. I think in general you want to test that the expected exception is thrown, and the exact message is really not necessary.

Which attribute do you use to handle exceptions in a test?

The HandleError Error attribute has a couple for properties that are very useful in handling the exception. ExceptionType: Type of exception to be catch. If this property is not specified then the HandleError filter handles all exceptions.


1 Answers

I've not heard of FakeItEasy or SubSpec (your tests look pretty funky, so I might check these out :)). However, I do use xUnit so this may be helpful:

I use Record.Exception with Assert.ThrowsDelegate

So something like:

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

Hope that helps.

like image 168
Steve Avatar answered Sep 17 '22 17:09

Steve