Try our conversational search powered by Generative AI!

Stefan Forsberg
May 7, 2010
  4609
(1 votes)

How do you setup different states that depends on EpiServer page structure?

Let’s say you have a page that acts as a container for news. The page simply lists all it’s children in a PageList. Now our GUI developer want us to have at least 21 pages to that they can check that the html they wrote for the paging functionality behaves ok. Soon after you need to verify that if the container doesn’t contain any children at all a message is displayed to inform the user that no news were found.

While these examples might seem somewhat silly the thing I’m getting at is that sometimes you (or your team) need your page structure to be in a certain state for you to verify and or test something.

 

Alternatives

So, what options do we have today to accomplish this?

 

1. The manual approach

This is basically just going into edit mode and create whatever structure(s) you need to verify your testing.

 

2. Creating lists programmatically

In the above examples we don’t really care what data is in the news items them self so we can create lists specifically for the test scenarios . Since we’re using a PageList we do have to make sure that we’re using a PageDataCollection and that the pages are correctly setup to not be filtered by FilterForVisitor.

 

3. Hooking up to DataFactory.LoadedChildren

This event enables us to change the resulting PageDataCollection. This results in much the same approach as number 2 above but keep in mind that this will also affect the way that the Episerver tree itself is generated too.

 

4. Using a custom page type builder.

This enables us to create a whole structure that behaves exactly like ordinary pages without them actually existing.

 

So how do these techniques measure up?

My problem with 1-3 is that modifying your “production” code and setup the state for your tests there almost always leads to a mess. You get those if debug statements (or even worse, code you have to remember to uncomment before deploying) and all in all it just feels fragile. Alternative 1 also can be tricky to do in a unit testing scenario since it can require manual fixing, which probably means that those test won’t run / pass very often.

Alternative 4 can be a good solution but it has some drawbacks. Depending on how much and what you want to test it might be slightly overkill to implement. A custom page provider also requires a enterprise license, which probably isn’t a problem in your local development but if you for some reason would like to use your faked structure on the live server (yes I know this is highly unlikely) you might not be able to do so. The final drawback is somewhat of a nitpick for me, but to use this in your unit tests you have to setup the whole configuration for episerver in your tests. Sure, it doesn’t take a trip to the database, but still.

 

Using DI and PTB 1.2

One of the new features in PageTypeBuilder 1.2 is the ability to inject dependencies into your TypedPageData classes. Joel has written a post about this here. I’ve done some simple proof on concepting about using this to setup structure, so please take the code for what it is.

To be able to controll the fetching of child pages we inject a dependency to IPageSource. Using the example above out news container could look like this

   1: [PageType("345D0610AE114BC5B5AAE8450D364757", Name = "News Container", Filename = "~/UI/Pages/NewsContainer.aspx")]
   2: public class NewsContainer : TypedPageData
   3: {
   4:     private readonly IPageSource pageSource;
   5:  
   6:     public NewsContainer(IPageSource pageSource)
   7:     {
   8:         this.pageSource = pageSource;
   9:     }
  10:  
  11:     public List<NewsItem> GetNews()
  12:     {
  13:         return pageSource
  14:             .GetChildren(PageLink)
  15:             .OfType<NewsItem>()
  16:             .ToList();
  17:     }
  18: }

 

We can now create “fake” classes to use for when we actually have the need to see the pages (for instance the scenario with paging described in the beginning of the post).

   1: public class FakeData : IPageSource
   2: {
   3:     public PageDataCollection GetChildren(PageReference pageLink)
   4:     {
   5:         var pageTypeID = PageTypeResolver.Instance.GetPageTypeID(typeof (NewsItem)).Value;
   6:         var pageType = PageType.Load(pageTypeID);
   7:  
   8:         InitializeBaseData initializer = new InitializeBaseData();
   9:  
  10:         PageDataCollection pageDataCollection = new PageDataCollection();
  11:         for (int i = 0; i < 50; i++)
  12:         {
  13:             var newsItem = new NewsItem { MainBody = "Hello" };
  14:             initializer.InitializePageData(newsItem, "SomePageName" + i, pageType, Guid.NewGuid(), new PageReference(5000 + i), pageLink, new List<string>(), string.Empty);
  15:             pageDataCollection.Add(newsItem);
  16:         }
  17:  
  18:         return pageDataCollection;
  19:     }
  20:  
  21:     public PageData GetPage(PageReference pageLink)
  22:     {
  23:         throw new NotImplementedException();
  24:     }
  25:  
  26:  
  27:     public PageData CurrentPage
  28:     {
  29:         get { throw new NotImplementedException(); }
  30:     }
  31: }

 

The class InitializeBaseData is more a less a copy of the reflected code from the method InitializePageData in PageProviderBase (minus the UrlSegment part since it’s method GetUrlFriendlySegment for some reason is internal). The reason for doing this is to make sure the PageData part of the TypedPageData has values to be able to use it with the PageList controll.

PageingFakeData

 

In our unit tests we can simply mock the IPageSource interface to test whatever scenario we want to test.

   1: [TestMethod]
   2: public void Some_pretty_redundant_test_that_doesnt_really_test_anything()
   3: {
   4:  
   5:     var pageSourceMock = new Moq.Mock<IPageSource>();
   6:     pageSourceMock.Setup(x => x.GetChildren(It.IsAny<PageReference>())).Returns(new PageDataCollection());
   7:     NewsContainer container = new NewsContainer(pageSourceMock.Object);
   8:  
   9:     Assert.IsTrue(container.GetNews().Count == 0);
  10: }

 

Hopefully I’ll have time to come back to this subject in a later post.

xoxo

May 07, 2010

Comments

Joel Abrahamsson
Joel Abrahamsson Sep 21, 2010 10:33 AM

Great post Stefan!

I would love to see a follow up where you combine this with StructureMap profiles creating a lifecycle aware site.

Please login to comment.
Latest blogs
Azure AI Language – Abstractive Summarisation in Optimizely CMS

In this article, I show how the abstraction summarisation feature provided by the Azure AI Language platform, can be used within Optimizely CMS to...

Anil Patel | Apr 18, 2024 | Syndicated blog

Fix your Search & Navigation (Find) indexing job, please

Once upon a time, a colleague asked me to look into a customer database with weird spikes in database log usage. (You might start to wonder why I a...

Quan Mai | Apr 17, 2024 | Syndicated blog

The A/A Test: What You Need to Know

Sure, we all know what an A/B test can do. But what is an A/A test? How is it different? With an A/B test, we know that we can take a webpage (our...

Lindsey Rogers | Apr 15, 2024

.Net Core Timezone ID's Windows vs Linux

Hey all, First post here and I would like to talk about Timezone ID's and How Windows and Linux systems use different IDs. We currently run a .NET...

sheider | Apr 15, 2024

What's new in Language Manager 5.3.0

In Language Manager (LM) version 5.2.0, we added an option in appsettings.json called TranslateOrCopyContentAreaChildrenBlockForTypes . It does...

Quoc Anh Nguyen | Apr 15, 2024

Optimizely Search & Navigation: Boosting in Unified Search

In the Optimizely Search & Navigation admin view, administrators can set a certain weight of different properties (title, content, summary, or...

Tung Tran | Apr 15, 2024