Since I last wrote about the Page Type Builder project we have started to use it in a real project. That means that the Page Type Builder project has left the experiment phase and the quality demands are a lot higher. Therefore I’d like to rewrite the whole thing using Test Driven Development. To be able to do so I’d like to be able to decouple my code from the database and underlying storage mechanisms in EPiServer CMS. In other words I’d like to mock DataFactory. That is however hard to do as it is a singleton.
While I could simulate a context where I could use the real DataFactory.Instance that would mean that I would be testing more than just my code (my unit) and therefore I wouldn’t really be performing unit tests, I would be performing integration tests (someone has been to a conference and heard the big boys talk :-)). While the terminology might not be that important, my tests would be overly complex, require a database and take too long to run. So, I needed to find a way to write tests that where independent of DataFactory.
I’ve also been considering wrapping DataFactory in a way where I create my own implementations of the most commonly used methods to be able to return PageData objects with the correct underlying type. That is myPageData is MyPageType should work for all objects returned from my methods.
Luckily, my need to mock DataFactory and my plans to wrap it coincided. Say hello to the PageDataFactory class! :)
PageDataFactory
In this version PageDataFactoy contains these public and static methods:
PageReference Save(PageData pageData, SaveAction saveAction)
PageReference Save(PageData pageData, SaveAction saveAction,
AccessLevel accessLevel)
PageData GetPage(PageReference pageReference)
PageData GetPage(PageReference pageReference,
ILanguageSelector languageSelector)
PageDataCollection GetChildren(PageReference pageReference)
PageDataCollection GetChildren(PageReference pageReference,
ILanguageSelector languageSelector)
PageData ConvertToTyped(PageData pageData)
PageDataCollection ConvertToTyped(
IEnumerable<PageData> pageDataCollection)
PageDataCollection GetPublishedChildren(PageReference pageReference)
List<T> GetPublishedChildrenOfPageType<T>(
PageReference pageReference)
void SetStoreInstance(IPageDataStore pageDataStore)
void SetPageTypeResolverInstance(IPageTypeResolver resolver)
void SetCheckPublishedStatusMethod(Func<PageData,
PagePublishedStatus, bool> method)
The first three sections of methods above should look familiar to anyone who has used DataFactory. The difference between them and those in DataFactory is that these will return PageData objects with the matching underlying type for pages whose page types has been declared in code. They will in turn delegate the actual fetching of the PageData objects to an instance of the IPageDataStore interface. Normally that means that they will delegate to an instance of the EPiServerPageStore, which in turn is just a direct wrapper around DataFactory.Instance.
That is, unless we specify that it should use an instance of another class that implements IPageDataStore (another addition to the project) with the SetStoreInstance method. In other words, we are now able to mock DataFactory.
Further, all of the Get methods will convert the PageData objects returned from the IPageDataStore instance to their correct types using the ConvertToTyped method (the fourth group above). This method will query an instance of a class that implements IPageTypeResolver to find out which type a PageData object should be of. Here to it will query a default implementation, ReflectionPageTypeResolver, which in turn will query the PageTypeBuilder class which has a dictionary of page type ids and types, unless we specify otherwise using the SetPageTypeResolverInstance method.
The fifth group of methods above, GetPublishedChildren and GetPublishedChildrenOfPageType are convenience methods that adds some (at least by me) often used functionality. Both will check that pages returned by GetChildren are published using a method that will call PageData.CheckPublishedStatus. To be able to test these methods easily, and offer extensibility it’s possible to specify another method that they should use using the SetCheckPublishedStatusMethod method.
Other changes since 0.6
Apart from the PageDataFactory class I’ve alse done some renaming and refactoring since version 0.6. Two major changes is that the TypedPageData.ToTyped method has been moved to PageDataFactory and renamed ConvertToTyped and that the type of existing properties are no longer automatically changed. The reason for not updating the type of existing properties is the same as for why I removed the functionality that automatically removed non declared properties in version 0.6, that it’s possible to do quite a lot of harm with the feature while it doesn’t save a lot of work.
Still, it would be nice to easily changes types of properties and remove non declared properties. One likely addition to the project, suggested by Peter Sunna, is to create a admin plugin that lists changes such as these and that offers a fast way to update page types so that they are in synch with the code.
Moving to CodePlex
As this project is starting to become more than just an experiment I decided to move the source code and binaries to a proper hosting. The source code can therefore now be found at the projects CodePlex site.
I will be using the CodePlex sites issue tracker to keep track of features that may be implemented and any bugs found. Anyone is welcome to add issues :)
Conclusion
Providing the above described methods in PageDataFactory feels like a good addition to the project. There is however still quite a lot of other methods that needs to be added. Oh, and then I also need to actually do the rewrite of the actual page type building code. Hopefully that will happen in the next version :)
As usual any and all feedback i greatly, enormously actually, appreciated!
Source code
The source code and a ready-to-use assembly can be found here.