Kentico 12: Design Patterns Part 11 - Unit Testing Custom Page Types
Tags: kentico, mvc, testing, csharp
Published: 2019-08-19 17:12:34

---
title: Kentico 12: Design Patterns Part 11 - Unit Testing Custom Page Types
published: true
description: Learn how to unit test Kentico custom Page Types, including "File"-type fields, and best practices for writing testable data access for Kentico 12 MVC apps.
tags: kentico, mvc, testing, csharp
series: Kentico 12 - Design Patterns
---

![Books and pages](https://thepracticaldev.s3.amazonaws.com/i/bya0yinp23e4bm4jvq1r.jpg)

<figcaption>Photo by <a href="https://unsplash.com/@impatrickt">Patrick Tomasso</a> on <a href="https://unsplash.com">Unsplash</a></figcaption>

Most of the time, when writing unit tests for your Kentico 12 MVC applications, you can rely on the [documented Kentico testing APIs](https://docs.kentico.com/k12sp/custom-development/writing-automated-tests/faking-info-and-provider-objects-in-unit-tests), like the `UnitTests` base class and `Fake<>()` method.

These APIs allow for Kentico database-dependent types and data sources to be stubbed, without relying on a live connection to the database 💪.

But some testing scenarios have solutions that require some insight into how Kentico's internals work 😮.

Below we'll look at an example of how to test code that uses a custom Page Type that has a database field of type "File".

> To learn more about Page Types, check out [Kentico's documentation](https://docs.kentico.com/k12sp/developing-websites/defining-website-content-structure/creating-and-configuring-page-types/creating-content-only-page-types) or [this post from Chris Hamm](https://www.bizstream.com/blog/february-2019/kentico-101-page-types) over at BizStream 👍.

---

## Defining a Scenario

### Custom Page Type - `EmployeeContent`

Let's set up a scenario which we'd like to test.

Assume we have an `EmployeeContent` custom Page Type with the following fields:

- `EmployeeContentID` - `int`
- `EmployeeContentImage` - `Guid`
- `EmployeeContentName` - `string`
- `EmployeeContentHireDate` - `DateTime`

Here is some of the code that Kentico auto-generates for this Page Type:

```csharp
public partial class EmployeeContent : TreeNode
{
    public const string CLASS_NAME = "Sandbox.EmployeeContent";

    private readonly EmployeeContentFields mFields;

    [DatabaseIDField]
    public int EmployeeContentID
    {
        get => ValidationHelper
            .GetInteger(GetValue("EmployeeContentID"), 0);
        set => SetValue("EmployeeContentID", value);
    }

    [DatabaseField]
    public Guid EmployeeContentImage
    {
        get => ValidationHelper
            .GetGuid(GetValue("EmployeeContentImage"), Guid.Empty);
        set => SetValue("EmployeeContentImage", value);
    }

    [DatabaseField]
    public string EmployeeContentName
    {
        get => ValidationHelper
            .GetString(GetValue("EmployeeContentName"), @"");
        set => SetValue("EmployeeContentName", value);
    }

    [DatabaseField]
    public DateTime EmployeeContentHireDate
    {
        get => ValidationHelper
            .GetDateTime(GetValue("EmployeeContentHireDate"), DateTimeHelper.ZERO_TIME);
        set => SetValue("EmployeeContentHireDate", value);
    }
}
```

After the initial class and property definition above, we can find the `EmployeeContentFields` nested-class, which gives us a more convenient way of accessing the fields not inherited from `TreeNode` (these would be the custom fields defined above).

```csharp
[RegisterAllProperties]
public partial class EmployeeContentFields :
    AbstractHierarchicalObject<EmployeeContentFields>
{
    private readonly EmployeeContent mInstance;

    public EmployeeContentFields(EmployeeContent instance) =>
        mInstance = instance;

    public int ID
    {
        get => mInstance.EmployeeContentID;
        set => mInstance.EmployeeContentID = value;
    }

    public DocumentAttachment Image =>
        mInstance.GetFieldDocumentAttachment("EmployeeContentImage");

    public string Name
    {
        get => mInstance.EmployeeContentName;
        set => mInstance.EmployeeContentName = value;
    }

    public DateTime HireDate
    {
        get => mInstance.EmployeeContentHireDate;
        set => mInstance.EmployeeContentHireDate = value;
    }
}
```

In addition to giving us quick access to the fields specific to our custom Page Type, `EmployeeContentFields` let's us treat certain types of fields as the data types we expected them to be 👍.

The `EmployeeContent.EmployeeContentImage` property and `EmployeeContent.EmployeeContentFields.Image` property are tell-tale signs of a custom Page Type with a `File` data-type field.

> You can read more about [managing Page Type fields](https://docs.kentico.com/k12sp/custom-development/developing-form-controls/reference-field-editor) in Kentico's documentation.

This is a uniquely named page attachment, as opposed to the `TreeNode.Attachments` property, that `EmployeeContent` inherits.

`TreeNode.Attachments` is a collection of attachments for the page which don't have named associations to the page itself. They aren't properties exposed on Page Type class - just a bag of Attachments 🤔.

This is different from fields on the Page Type that have a data-type specified as "File". Since these are specific fields they will have specific properties on the Page Type class that allow you to access the Attachments 🧐.

Notice that while `EmployeeContentImage` is type `Guid` (which is the `Guid` of the image attachment associated with this field), in the `EmployeeContentFields` class we have an `Image` property of type `DocumentAttachment`.

```csharp
[DatabaseField]
public Guid EmployeeContentImage
{
    get => ValidationHelper
       .GetGuid(GetValue("EmployeeContentImage"), Guid.Empty);
    set => SetValue("EmployeeContentImage", value);
}
```

vs

```csharp
public DocumentAttachment Image =>
    mInstance.GetFieldDocumentAttachment("EmployeeContentImage");
```

While the `Guid` is the true raw value stored in the database column, the `DocumentAttachment` is probably what we want to interact with when using this custom Page Type class.

> `DocumentAttachment` gives us access to the `.GetPath()` method which uses Kentico's internals to build a URL to the attachment 👏, as opposed to doing the string building of URL ourselves.

This `Image` property does help us out, but it also makes our class tricky to test. This property is read-only! We can't assign a test value to an instance of `EmployeeContent` that we might create for testing 😞.

Also, what does `.GetFieldDocumentAttachment()` do? We can't intercept this call so we'll need to rely on Kentico's testing APIs to help 🙄.

### Request Handler - `EmployeesListPageRequestHandler`

Following the [Mediator pattern](https://blogs.msdn.microsoft.com/cdndevs/2016/01/26/simplifying-development-and-separating-concerns-with-mediatr/) we move our business logic and request processing out of our MVC Controller and into a Request Handler.

> We'll be using the [Mediatr](https://github.com/jbogard/MediatR) library to help us build out this infrastructure.

This Request Handler class, which we will name `EmployeesListPageRequestHandler`, will get a request from a Controller, process it, and return a View Model as a response.

We could retrieve the data from the auto-generated `EmployeeContentProvider` but that's going to likely force us to write an integration test for this Request Handler.

Instead we will hide the data-access implementation details behind [a facade](https://en.wikipedia.org/wiki/Facade_pattern).

It could be a Repository, a Query, or a Dispatcher which maps a Query to a Query Handler (similar to how Mediatr works).

The point is, you'll want some sort of abstraction to keep your Request Handler loosely coupled to your data access technology.

#### A Quick Note on Repositories ... <a name="quick-note-on-repositories"></a>

I'm not a fan of custom written Repositories for several reasons.

1. We often work with Object Relational Mappers (ex: Entity Framework or Kentico's `ObjectQuery<T>`, `DocumentQuery<T>`, and static `*Provider` types) which are Repositories already, so [wrapping a Repository in another one](https://lostechies.com/jimmybogard/2012/10/08/favor-query-objects-over-repositories/) feels like an abuse of the pattern.

1. Custom written Repositories become large bags of methods all dealing with the same type (ex: `EmployeeContent`) but for different purposes. They break the Single Repsonsibility Principle and typically don't have a reason to contain all the methods they contain since the Repository classes themselves don't have any shared state between methods.

This is why I instead favor using the Command / Query Resposibility Segregation pattern and using a [Query, QueryHandler, and a Dispatcher](https://weblogs.asp.net/shijuvarghese/cqrs-commands-command-handlers-and-command-dispatcher) 💪.

I'm going to use a simple `Query` below, but use the pattern you're most familiar with 🤗. 

And, of course, we'll be using Constructor-based Dependency Injection for testability 😎!

---

Here is the simple implementation of our Request Handler, which is the code we will be writing a unit test for.

```csharp
public class EmployeesListPageRequestHandler
    : RequestHandler<EmployeeListPageRequest, EmployeeListPageViewModel>
{
    private readonly IEmployeeQuery query;

    public EmployeesListPageRequestHandler(IEmployeesQuery query)
    {
        this.query = query;
    }

    protected override EmployeeListPageViewModel Handle(
        EmployeeListPageRequest request)
    {
        IEnumerable<EmployeeContent> employees = query.Execute(request.EmployeeCount);

        if (employees is null)
        {
            return new EmployeeListPageViewModel(
                employees: Enumerable.Empty<EmployeeContent>(),
                count: 0);
        }

        var employeeViewModels = employees.Select(e =>
        {
            string imageUrl = e.Fields.Image.GetPath();

            new EmployeeViewModel(
                name: e.Fields.Name,
                imageUrl: imageUrl,
                hireDate: e.Fields.HireDate
        }));

        return new EmployeeListPageViewModel(
                employees: employeeViewModels,
                count: employeeViewModels.Count());
    }
}
```

This class retrieves `EmployeeContent`, presumably, from the database, handles invalid data, and returns a valid View Model instance.

Pretty normal use-case!

## Setting Up Our Test

Now that we've scaffoled out all the code we want to test and identified they key areas our test will interact with, let's get to creating our unit test 🥳!

### Creating the Test Class - `EmployeesListPageRequestHandlerTests`

First things first - let's create a test class and test method following [Kentico's documentation for unit tests](https://docs.kentico.com/k12sp/custom-development/writing-automated-tests/faking-info-and-provider-objects-in-unit-tests).

```csharp
using CMS.Tests;
using NUnit.Framework;
using using System.Threading.Tasks;

[TestFixture]
public class EmployeesListPageRequestHandlerTests : UnitTests
{
    [Test]
    public async Task Handle_Will_Initialize_ViewModel()
    {
        // Arrange

        // Act

        // Assert
    }
}
```

We need to inherit from `UnitTests` in the `CMS.Tests` namespace.

This will let us tell Kentico we want this test to work with data that would normally come from the database (our custom Page Type instances), but we will providing the data ourselves within the test 👍.

We will also separate our test method into 3 phases - Arrange, Act, and Assert.

### Arranging Our Test - AutoFixture, NSubstitute, and Kentico Fakes

Now let's begin the "Arrange" phase of the test.

We will be using [AutoFixture](https://github.com/AutoFixture/AutoFixture) to create values for our test.

Most of the time the actual values used in a test are not important.

The values are passed around and maybe modified, but as long as the values at the end of the test are consistent with the values at the beginning - given the process of the Subject Under Test (`sut`) - we don't really care what the original values were.

AutoFixture allows us to create valid values on-the-fly.

Here is an example below:

```csharp
using AutoFixture;

...

// Arrange

var fixture = new DomainFixture();

string name = fixture.Create<string>();

// Do something with name ...
```

Now we need to tell Kentico that we want to create fake instances of our `EmployeeContent` Page Type and we will supply them as values returned from our `EmployeesQuery`.

First, let's create the fake `EmployeeContent` instances.

We need the following `using` statements for namespace imports from Kentico:

```csharp
using CMS.DataEngine;
using CMS.DocumentEngine;
using CMS.DocumentEngine.Types.Sandbox;
using CMS.Tests;
using Tests.DocumentEngine;
```

We will use the `Fake()` method we have access to by inheriting from `UnitTests` to tell Kentico we want to fake access to some data.

We will also use the `DocumentType<T>()` extension method to tell Kentico what type of Page Type we will be faking.

```csharp
Fake().DocumentType<EmployeeContent>(EmployeeContent.CLASS_NAME);
```

The above line only tells Kentico our intentions - it doesn't actually create any instances of `EmployeeContent`, let's do that now:

```csharp
var employee = TreeNode.New<EmployeeContent>().With(e =>
{
    e.Fields.Name = fixture.Create<string>();
    e.Fields.HireDate = fixture.Create<DateTime>();
    e.EmployeeContentImage = fixture.Create<Guid>();
});
```

You'll notice that we don't assign a value to `e.Fields.Image` because it's read-only, so instead we assign a `Guid` to its backing field, `EmployeeContentImage`.

But how do we turn that `Guid` into an instance of `DocumentImage` when we call `EmployeeContent.Fields.Image` 🤔?

We will need Kentico to do that for us, but that will require mocking a little more data:

```csharp
var attachmentGuid = fixture.Create<Guid>();

Fake<AttachmentInfo, AttachmentInfoProvider>()
    .WithData(new AttachmentInfo
    {
        AttachmentGUID = attachmentGuid
    });

Fake().DocumentType<EmployeeContent>(EmployeeContent.CLASS_NAME);

var employee = TreeNode.New<EmployeeContent>().With(e =>
{
    e.Fields.Name = fixture.Create<string>();
    e.Fields.HireDate = fixture.Create<DateTime>();
    e.EmployeeContentImage = attachmentGuid;
});
```

Notice how we use the `attachmentGuid` value both for the faked `AttachmentInfo.AttachmentGUID` property and the `EmployeeContent.EmployeeContentImage` property.

This will allow Kentico to tie these two instances together at test-runtime.

As it turns out `TreeNode.GetFieldDocumentAttachment()` calls `AttachmentInfoProvider.GetAttachmentInfo()`, passing the `Guid` of the attachment to be retrieved.

So, as long as we fake an `AttachmentInfo` using `AttachmentInfoProvider`, we will be able to setup the state of our test to work entirely in memory and not need a database 🤘🎉🔥.

---

Now we need a way to supply the `employee` we created above as the value our `IEmployeeQuery` returns for the `Execute()` call.

We can use [NSubstitute](https://nsubstitute.github.io/) to stub our interfaces with minimal implementations that only return values without performing any operations.

```csharp
using NSubstitute;

// Arrange

var query = Substitute.For<IEmployeeQuery>();

query
    .Execute(Arg.Is(request.EmployeeCount))
    .Returns(new [] { employee });

```

Let's put all of the pieces of the Arrange phase of our test together:

```csharp
[Test, AutoDomainData]
public async Task public async Task Handle_Will_Initialize_ViewModel()
{
    // Arrange

    var attachmentGuid = fixture.Create<Guid>();

    Fake<AttachmentInfo, AttachmentInfoProvider>()
        .WithData(new AttachmentInfo
        {
            AttachmentGUID = attachmentGuid
        });

    Fake().DocumentType<EmployeeContent>(EmployeeContent.CLASS_NAME);

    var employee = TreeNode.New<EmployeeContent>().With(e =>
    {
        e.Fields.Name = fixture.Create<string>();
        e.Fields.HireDate = fixture.Create<DateTime>();
        e.EmployeeContentImage = attachmentGuid;
    });

    var request = fixture.Create<EmployeeListPageRequest>();

    var query = Substitute.For<IEmployeeQuery>();

    query
        .Execute(Arg.Is(request.EmployeeCount))
        .Returns(new [] { employee });

    IRequestHandler<EmployeeListPageRequest, EmployeeListPageViewModel> sut =
        new NewsRequestHandler(query);

    // Act

    // Assert
}
```

---

### Acting Out Our Test Case

Now for the simple part - the Act phase:

```csharp
var viewModel = await sut.Handle(request, default);
```

Yup, that's it. All the work typically goes into the Arrange and Assert phases of our test since the Act phase has already been written - it's the body of the method you are testing!

### Asserting On Our Test Results - FluentAssertions

We now need to Assert that the state of our test data is exactly what we expect it to be after the Act phase.

We can do this using .NET's built-in Assert calls (which are in the `Microsoft.VisualStudio.TestTools.UnitTesting` namespace), but `NUnit` already supplies us some in the `NUnit.Framework` namespace.

That said, my preference is to use a library like [FluentAssertions](https://fluentassertions.com/introduction) to provide a more Behavior Driven Development style of assertions which, I find, makes the test more readable 😉.

FluentAssertions uses extension methods to provide a syntax that looks as follows:

```csharp
SomeViewModel viewModel = ...

viewModel.Should().NotBeNull();

viewModel.FirstName.Should().Be("abc");
```

So let's use FluentAssertions to Assert against the state of our test after we've acted upon our Subject Under Test:

> I'll add in pieces from the Arrange and Act phases for reference.

```csharp
// Arrange

...

var employee = TreeNode.New<EmployeeContent>().With(e =>
{
    e.Fields.Name = fixture.Create<string>();
    e.Fields.HireDate = fixture.Create<DateTime>();
    e.EmployeeContentImage = attachmentGuid;
});

...

// Act

var viewModel = await sut.Handle(request, default);

// Assert

viewModel.Count.Should().Be(1);

var employeeViewModel = viewModel.Employees.First();

employeeViewModel.Name.Should().Be(employee.Fields.Name);
employeeViewModel.HireDate.Should().Be(employee.Fields.HireDate);

employeeViewModel.ImageUrl
    .Should()
    .Contain(employee.EmployeeContentImage.ToString());
```

Our assertions here are stating the following things:

- There should only be (1) employee in the View Model.
- The values of the `EmployeeViewModel` should match up with the values of the `EmployeeContent` instance.
- The `EmployeeViewModel.ImageUrl` should contain the `Guid` as a string matching the `Guid` of `EmployeeViewModel.EmployeeContentImage`.

For the last assertion we could be more specific and ensure the URL created by Kentico's `DocumentAttachment.GetPath()` method matches what we expect it to be, character by character, but I'm ok with what we have.

## Summary

Look at the beautiful mess we've made 🤣!

We looked at some design patterns that will help us architect our Kentico MVC application, and set up our business logic (mostly data access at this point), to be 100% testable 👍!

We also used Kentico's testing APIs to help us mock data and ensure our test could be run as a Unit Test and not an Integration Test 👍.

This will make the test faster to run and less brittle as our application changes 👍.

Finally we leveraged some .NET testing libraries (AutoFixture, NSubstitute, and FluentAssertions) to help us focus on the key phases of our test - Arrange, Act, and Assert 👍.

> We left out a key test scenario - what if the data returned by our `IEmployeesQuery` is `null`? We handle this in our Request Handler, but we don't test for this scenario.

> This test case should be a separate test method where we Arrange, Act, and Assert all over again, but this time with the Arrange and Assert phases set up for a `null` data scenario.

> I'll leave this up to you to implement 🤓!

If you have any feedback, or recommended ways you like to write your tests, I'd love to hear about it in the comments below.

Thanks for reading!

---

If you are looking for additional Kentico content, checkout the Kentico tag here on DEV:

{% tag kentico %}

Or my Kentico blog series:

- [Kentico 12: Design Patterns](https://dev.to/search?q=Kentico%2012%20-%20Design%20Patterns)
- [Kentico CMS Quick Tips](https://dev.to/search?q=Kentico%20CMS%20Quick%20Tip)