I have been a user of Machine.Specifications or Mspec for awhile now, and have been pretty happy with how much more readable it makes my unit testing.
If you are not familiar with Mspec it is a testing framework for context/specification that uses delegates to setup the Act, Arrange, & Assert pattern.
There are several good getting started guides if this is new to you, but here is a basic example of the structure.
public class When_a_content_admin_asks_for_a_non_existent_page{ Establish that; Because of; It Should_check_the_repository; It Should_present_a_blank_add_content_screen; It Should_auto_populate_the_url_field; }
Now of course to do unit testing you must be able to do mocking/stubbing/faking etc…, I am normally a user of Moq and that is what I use in my Mspec test to establish my mocks. While it works well, all the noise it takes to arrange all of my mocks at times bothers me. While the noise was irritating I just dealt with it because setting up mocks is just something you have to do, but luckily I recently discovered somebody else had the motivation topublic class When_a_content_admin_asks_for_a_non_existent_page
{
Establish that = () =>
{
var auth = new Mock<Authorization>();
auth.Setup(x => x.IsContentAdmin(GivenIt.IsAny<HttpContextBase>()))
.Returns(true);
_repo = new Mock<ContentRepository>();
_repo.Setup(x => x.Exists("a/bogus/url"))
.Returns(false);
_controller = new MeekController(_repo.Object, auth.Object);
};
Because of = () =>
_result = _controller.Manage("/a/bogus/url");
It Should_check_the_repository = () =>
_repo.Verify(x => x.Exists("a/bogus/url"), Times.Once());
It Should_present_a_blank_add_content_screen = () =>
_result.AssertViewRendered().ForView("Manage");
It Should_auto_populate_the_url_field = () =>
(_result.AssertViewRendered().Model as Content.Manage).ManageUrl.ShouldNotBeEmpty();
static ActionResult _result;
static MeekController _controller;
static Mock <ContentRepository> _repo;
}
You can see that I am Mocking both an Authorization and a ContentRepository interface, with the ContentRepository defined as a field so I can assert upon it later. Both mocks are passed into the class constructor of my system under test (SUT). Now while this is not a ton of noise we can trim it down to a more readable state with Machine.Fakes, below is my updated test.
public class When_a_content_admin_asks_for_a_non_existent_page : WithSubject<MeekController>{ Establish that = () => { The<Authorization> () .WhenToldTo(x => x.IsContentAdmin(GivenIt.IsAny<HttpContextBase>())) .Return(true); The<ContentRepository> () .WhenToldTo(x => x.Exists("a/bogus/url")) .Return(false); }; Because of = () => _result = Subject.Manage("/a/bogus/url"); It Should_check_the_repository = () => The<ContentRepository>().WasToldTo(x => x.Exists("a/bogus/url")).OnlyOnce(); It Should_present_a_blank_add_content_screen = () => _result.AssertViewRendered().ForView("Manage"); It Should_auto_populate_the_url_field = () => (_result.AssertViewRendered().Model as Content.Manage).ManageUrl.ShouldNotBeEmpty(); static ActionResult _result; }
Conclusion… I am a happy camper that has to type even less now.
Comments
Posted On
Mar 17, 2011Posted By
Phil LedgerwoodThis was great, Brian. I’ve been trying to de-machine MSpec, and this was very helpful. I’ve been using FakeItEasy lately for my mocking needs, and it has been much more readable than, say, Moq, but I think I’ll give this a whirl and see how I like it.
Posted On
Mar 17, 2011Posted By
Brian WigfieldI just updated my code samples I did not realized when I pasted them in it turned all of my generics into HTML tags.