How to test for exceptions thrown using xUnit, SubSpec and FakeItEasy
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>();
Related videos on Youtube
m_collard
Updated on September 15, 2022Comments
-
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 over 6 yearsI'm getting a "Action does not contain a definition for ShouldThrow..." What reference/assembly do I need to include?
-
duyn9uyen almost 2 yearsact.Should().Throw<Exception>();