Kentico 12: Design Patterns Part 1 - Writing Testable Code
Tags: aspnet, unittesting, kenticodevelopers, kentico
Published: 2019-06-01 01:10:29

---
title: Kentico 12: Design Patterns Part 1 - Writing Testable Code
published: true
tags: aspnet,unit-testing,kentico-developers,kentico
canonical_url: https://medium.com/@seangwright/kentico-12-design-patterns-part-1-26126243ed10
series: Kentico 12 - Design Patterns
description: Learn how identify un-testable dependencies and write testable code
---
![](https://cdn-images-1.medium.com/max/1024/0*xpmHwds5Fbvdv7PA)<figcaption>Photo by <a href="https://unsplash.com/@nicolasthomas?utm_source=medium&amp;utm_medium=referral">Nicolas Thomas</a> on <a href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption>

## The Good: Why We Love Kentico 😻

In my opinion, Kentico has always been designed to make its users productive. This is true for both the classic Portal Engine drag-and-drop UI builder and the .NET libraries developers can use to interact with the CMS.

Do you need to get user data from the database? Call the static provider class with `UserInfoProvider.GetUsers();`. ✔️

Do you need to know which site the current request is running under? Use the static context accessor `SiteContext.CurrentSiteName;`. ✔️

Want to ensure some data that is accessible as type object is actually the int value you originally stored? Wrap it in the static utility method call `ValidationHelper.GetInteger(originalData, 0);`. ✔️

The key thing to notice about all these calls is that they are `static` methods often on `static` classes.

These classes don’t require instantiation, we don’t need to understand their dependency graph, they come to us pre-packaged and ready to use, and are truly global values as long as we have access to the `.dll` in which they are deployed.

The implication of this design is that all of the above tools that developers have access to, for building complex web sites on the Kentico CMS, can be discovered and leveraged as simply as possible. 🙌

## The Bad: Skeletons in the Closet 💀

There is a dark side to this happy world of `static`, global access.

These types are often tightly coupled to their dependencies, some can only be used in a specific context (that of a live request going through the ASP.NET request pipeline), and can be difficult — if not impossible — to unit test. 😱

> From here on I’m going to refer to things being ‘testable’ or ‘un-testable’ by which I mean unit testing specifically.

This consequence isn’t exactly Kentico’s fault.

ASP.NET Web Forms was not a technology that encouraged testing or a decoupled architecture. It was built to ensure optimal productivity for Windows Forms desktop developers moving to building web applications.

Kentico is built on Web Forms and therefore is going to mimic its patterns and priorities — ease of use, abstracting away the ‘web’ part of web development, and access to static "ambient context" globals like `HttpContext`.

> If you’ve never heard of Ambient Context before, you can read up on the [design pattern here](https://aabs.wordpress.com/2007/12/31/the-ambient-context-design-pattern-in-net/). One item to note is under the Consequences section where it is stated “The consequences to the system of making use of an ambient context object will be dependent on the problem domain”. Here "problem domain" is equivalent to "real running ASP.NET site processing an active HTTP request".

But now we’re starting a new era of Kentico development where our code is going to be run both in the Web Forms CMS architecture and the newer MVC architecture.

MVC was designed to separate concerns, decouple declarative UI from procedural logic, and allow for patterns like Inversion of Control, Dependency Injection and Composition instead of Inheritance. 🤓

How can we, as developers, bridge the gap between the powerful set of libraries and tools provided by Kentico to integrate with the CMS and the best-practice architectural patterns allowed (and encouraged) by MVC? 🥺

> Not all of Kentico’s classes have these issues. For example, `ValidationHelper` is static but also basically a pure function that attempts to convert a value of type `object` to a specific type. It can safely be used anywhere in your code and will give the same results at runtime that it will at test time.

## But Wait, There’s Hope! 🤗

Let’s look at a simple example of how to encapsulate the convenient but un-testable parts of our traditional Kentico applications.

For this example, we are going to look at accessing Kentico’s settings API which allows for configuration, normally stored in `<appSettings>` in the `web.config` of a site to be stored in Kentico’s database.

How might you normally get this data for the site of the current request? 🤔Maybe the following:

```csharp
string settingValue = SettingsKeyInfoProvider.GetValue("someKeyString", SiteContext.CurrentSiteName);
```

While Kentico does provide us a way to test `SettingsKeyInfoProvider.GetValue()` [using `Fake<>` in unit tests](https://docs.kentico.com/k12/custom-development/writing-automated-tests/faking-info-and-provider-objects-in-unit-tests), there is no way to unit test `SiteContext`.

`SiteContext`, along with all the other convenient static `***Context` types, are un-testable. They require a real ASP.NET application with a live request in order to work correctly, and because they are static, we cannot mock them. 😒

How do we build our own API that provides access to this data but doesn’t create a dependency on `SiteContext`?

## Interfaces are Here to Help

The example code below introduces our first and best tool to make our applications more testable: interfaces.

In C#, interfaces can’t be implemented by `static` classes, so that immediately saves us from ending up in the situation we already find ourselves in.

But they also provide a seam into which we can insert existing calls to Kentico’s `static` classes and methods when needed, without exposing that implementation. No need to throw the baby out with the bathwater. We don’t want to re-write the CMS; we just want it to be testable. 😉

{% gist https://gist.github.com/seangwright/65753463c11f768583c00012d18ddc5e %}

This interface defines a way to access the settings configured for Kentico, both globally and per-site when running a multi-site instance.

Now we have an interface that we can implement however we choose, and as long as our MVC code takes a dependency on this interface (likely through Dependency Injection), we can ensure our code is testable. 👍

## Let’s Implement

Okay, so we’ve basically moved the goal post. Our MVC code will depend on `IKenticoSettingConfigProvider`, but we will need an implementation for this interface at some point.

Our first thought might be to create a class that directly uses the example `SettingsKeyInfoProvider.GetValue()` call above.

{% gist https://gist.github.com/seangwright/948aba93073d2fdbb0e625f11dd81c26 %}

This certainly works, but if our `KenticoSettingConfigProvider` implementation class starts to have any complex logic, we are going to want to test it as well.

Like I mentioned above, while `SettingsKeyInfoProvider.GetValue()` is testable, `SiteContext` is not — so our initial implementation of this class is, again, not testable. 🤦🏾‍♂️

## A Quick Aside: What’s the Value? 💲

Even if the amount of logic in our implementation class is low and we don’t feel the need to write tests for it, there’s still value in designing it with testing in mind.

To effectively test code, we need to identify dependencies and ensure those dependencies can be mocked or isolated from the code we want to test. This identification process is valuable in itself. By identifying these dependencies, we come to realize what assumptions our code makes about how and where it can be run. 🌟

What does it mean when your code takes a dependency on `MemebershipContext` or `HttpContext`?

Are these always available when your code is executing? Will they always have the values you expect? What about in a Scheduled Task or a background thread? 🤔

I remember writing some logging code that accessed `HttpContext` to log additional request details. Only later did I find out that `HttpContext` doesn’t always exist when the logging happens. This caused my logging code to throw exceptions. I made assumptions about where and how my code was run that did not hold true.

Had `HttpContext` not been buried deep in a logging method, but instead was specified as a constructor dependency, I would have had a better chance of understanding my failed use-case ahead of time.

## Writing for Testability 👩‍💻

Let’s look at how we can make our `KenticoSettingConfigProvider` class testable.

We know `SiteContext` isn’t testable, so let’s stop using it directly and instead create a seam we can hide the implementation details behind.

{% gist https://gist.github.com/seangwright/43fff4642e30658b8895a7baf279573b %}

Here we create an `ISiteContext` interface that exposes the same values we would need from `SiteContext`, but since it’s an interface, we can mock it.

If we want our `KenticoSettingConfigProvider` to take a dependency on the mocked version of our `ISiteContext` when under test, we need to be able to supply that mocked version.

The best way to do this is through constructor Dependency Injection.

{% gist https://gist.github.com/seangwright/be623bae6070ac64d99a91f3f06ab934 %}

You can see above how we take a dependency on `ISiteContext` via the constructor of `KenticoSettingConfigProvider`.

> If you are wondering about the `Guard.Against.Null()` call in the constructor above, take a look at [Steve Smith’s GuardClauses library](https://github.com/ardalis/GuardClauses). It’s a great way to guard against invalid parameters for constructors or methods by throwing an exception if the requirements of the guard are not met.

> I love how it’s declarative, simple, and easy to reason about. I use them in all the code I write and I write tests that ensure they are in place.

The advantage we gain here is that we can simulate the site of the current request in our tests. When we test the methods of `KenticoSettingConfigProvider` we will mock `ISiteContext` with an implementation that, for example, always returns `"MySite"` for the `SiteName` property.

If we `Fake<SettingsKeyInfo, SettingsKeyInfoProvider>` and `Fake<SiteInfo, SiteInfoProvider>` to match up with `"MySite"`, then our `ISiteContext` will supply a `SiteName` that will match up with the settings we expect our class to return. 👍

## The Real Context 🔩🔧

Okay, so we’ve now abstracted our MVC code from the static types in Kentico’s libraries through the `IKenticoSettingConfigProvider` interface, and also abstracted our `KenticoSettingConfigProvider` away from the un-testable `SiteContext` through the `ISiteContext` interface.

Let’s implement `ISiteContext` with something that will actually work at runtime.

{% gist https://gist.github.com/seangwright/77d37435676efb563e49a84483a43df5 %}

Well, this is pretty simple, isn’t it? We forward the properties of our interface to the properties of the `SiteContext`.

My recommendation is to use an interface like `ISiteContext` throughout your MVC codebases whenever you need access to that Kentico data/context goodness, and leave the real `SiteContext` as an implementation detail hidden behind `ISiteContext`. 👩🏾‍🔧

This will help make your code more composable, help you identify the dependencies your code has on external data and resources, and perhaps most importantly, help make your code more testable.

You get to leverage the power of Kentico without being subject to the drawbacks of a classic ASP.NET Web Forms influenced architecture! 👏🏽

## What’s Next?

Phew 🚴🏽‍♀️. That was a bit of work, but we’re in a better place because of it. 🗺️

We’ve learned how to identify and isolate the un-testable pieces of Kentico’s infrastructure, and written our own testable library code.

So where do we go from here? 🧗🏻

In my next post, I’ll introduce some techniques and tools to help you test your Kentico code effectively while also reducing boilerplate. 👋🏾

[Kentico 12: Design Patterns Part 2](https://dev.to/seangwright/kentico-12-design-patterns-part-2-writing-unit-tests-1f8n)