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

10,362

Solution 1

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

Solution 2

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.

Solution 3

This is one way to do it in FakeItEasy.

Action act = () => someObject.SomeMethod(someArgument);
act.ShouldThrow<Exception>();
Share:
10,362

Related videos on Youtube

m_collard
Author by

m_collard

Updated on September 15, 2022

Comments

  • m_collard
    m_collard over 1 year

    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

  • Emmanuel John
    Emmanuel John over 6 years
    I'm getting a "Action does not contain a definition for ShouldThrow..." What reference/assembly do I need to include?
  • duyn9uyen
    duyn9uyen almost 2 years
    act.Should().Throw<Exception>();