The Fakes module in the EPiAbstractions project provides fake implementations of the IPageRepository, IPageReferenceFacade and IEPiServerContext interfaces allowing you to easily write unit tests for EPiServer CMS sites without having to create mock objects yourself.
The module that ties it all together when testing
I have previously written about the new version of EPiAbstractions in general, the Opinionated module and the FixtureSupport module. The final piece of the EPiAbstractions puzzle is the Fakes module with which you can basically create an in-memory site and thereby creating unit tests that are more easy to read and understand than otherwise when you have to do a lot of mocking black magic.
Components
The Fakes module currently consists of three classes, FakePageReferenceFacade, FakePageRepository and FakeEPiServerContext. The two first, FakePageReferenceFacade and FakePageRepository are basically in-memory implementations of the IPageReferenceFacade and IPageRepository interfaces. If you instantiate them they won’t contain any data but you can certainly use them. For instance you can do things like this:
var page = CreatePage.OfType<PageData>(); var repository = new FakePageRepository(); var pageRef = repository.Publish(page); page = repository.GetPage(pageRef);
FakeEPiServerContext
To make things really easy when testing the FakeEPiServerContext class comes with a factory method, Create, that will not only return an implementation of the IEPiServerContext interface but will also set up it’s containing PageReference and PageRepository with a root page, a wastebasket page and a start page.
To get the start page you can do this:
cmsContext = FakeEPiServerContext.Create(); var startPage = cmsContext.PageRepository .GetPage(cmsContext.PageReference.StartPage); // result will be true var result = startPage.ParentLink == cmsContext.PageReference.RootPage;The Create method also has a typed overload with which you can specify the type of the start page.
cmsContext = FakeEPiServerContext.Create<StartPage>(); var startPage = cmsContext.PageRepository .GetPage<StartPage>(cmsContext.PageReference.StartPage);
Limitations to FakePageRepository
Currently there is some work that remains to be done as I have basically implemented the different methods in FakePageRepository as I’ve needed them myself or as someone else has expressed a need for them. Those that aren’t implemented, primarily overloads that take a language selector as a parameter, will throw a NotImplementedException. Also, the methods that normally filter by access rights and publication status doesn’t do that at all.
A real world usage example
In my post about the Opinionate module I used an example of a presenter for a breadcrumbs widget. A test for that presenter written using MSpec that utilizes the Fakes module could look like this:
[Subject("Breadcrumbs")] public class when_viewing_a_page_that_is_child_of_the_startpage { static TypedPageData currentPage; static FakeView<BreadcrumbsModel> view; Establish context = () => { var cmsContext = FakeEPiServerContext.Create(); currentPage = CreatePage.OfType<TypedPageData>() .ThatIs().ChildOf(cmsContext.PageReference.StartPage) .AndHas().PageName("da page name"); cmsContext.PageRepository.Publish(currentPage); view = new FakeView<BreadcrumbsModel>(); new BreadCrumbsPresenter(view, currentPage, cmsContext); view.RaiseLoadEvent(); }; It should_contain_a_single_link = () => view.Model.Breadcrumbs.Count.ShouldEqual(1); It should_contain_a_link_with_text_equal_the_current_pages_name = () => view.Model.Breadcrumbs.First().Text .ShouldEqual(currentPage.PageName); }
The syntax of MSpec aside I think that the setup of the test (the context delegate) is fairly easy to understand. We create a EPiServerContext, create a new page that is a child of the start page and has a specified name. Finally we publish the page, create view (using a utility class not included here), create a new presenter and raise the load event of the view. Compare that to how the context would have looked if we hadn’t been using EPiAbstraction’s Fakes and FixtureSupport modules and instead relied on the usage of a mocking framework (Moq in this case):
Establish context = () => { var fakeContext = new Mock<IEPiServerContext>(); var fakePageReference = new Mock<IPageReferenceFacade>(); fakeContext.SetupGet(c => c.PageReference) .Returns(fakePageReference.Object); var startPageRef = new PageReference(1); fakePageReference.SetupGet(p => p.StartPage) .Returns(startPageRef); // We need to mock currentPage as it's of an //abstract type currentPage = new Mock<TypedPageData>().Object; currentPage.PageName = "da page name"; currentPage.ParentLink = startPageRef; view = new FakeView<BreadcrumbsModel>(); new BreadCrumbsPresenter(view, currentPage, fakeContext.Object); view.RaiseLoadEvent(); };
Not only is the first version several lines shorter, I think it’s feels far more intuitive to read and captures the essence of the test/specification much better.
PS. For updates about new posts, sites I find useful and the occasional rant you can follow me on Twitter. You are also most welcome to subscribe to the RSS-feed.
Similar articles
- EPiAbstractions.FixtureSupport – Easily create test data for EPiServer CMS
- EPiAbstractions.Opinionated – A wrapper for EPiServer CMS and Page Type Builder
- Introducing EPiMVP – A Framework for using Web Forms MVP with EPiServer CMS
- A toolset for building testable and flexible EPiServer CMS sites
- EPiMVC – A framework for using EPiServer CMS with ASP.NET MVC
- More testability to the people with EPiAbstractions!
- Developing with Page Type Builder – Getting Started
- One small step for EPiServer, one giant leap for our code
My book
Want a structured way to learn EPiServer 7 development? Check out my book on Leanpub!
Comments
comments powered by Disqus