Kentico CMS Quick Tip: Faking A Live Site For Integration Testing
Tags: kentico, testing, cms, aspnet
Published: 2019-11-11 13:50:10

---
title: Kentico CMS Quick Tip: Faking A Live Site For Integration Testing
published: true
description: Learn how to simulate a live Kentico EMS site when running integration tests.
tags: kentico, testing, cms, aspnet
series: Kentico Quick Tips
cover_image: https://thepracticaldev.s3.amazonaws.com/i/80gwc2mwsmoq68v1f48c.jpg
---

<figcaption>Photo by <a href="https://unsplash.com/@mihaly_koles">Mihály Köles</a> on <a href="https://unsplash.com">Unsplash</a></figcaption>

## Overview

- Integration tests give confidence in complex code interactions
- Some of Kentico's APIs are difficult to test, because they depend on a live ASP.NET application context
- We can fake this context if we know which parts are accessed during our test
- Testing Kentico's `ShoppingService` lets us explore how the E-Commerce functionality works and verify the results of our custom code

---

## Kentico Integration Tests

Integration tests in Kentico projects are perfect for simulating interactions between classes that depend on external resources, namely the database.

Many interactions with Kentico's APIs can be performed in unit tests, but some (like `UserInfoProvider.IsUserInRole`) require a real database connection 🤔.

Other times, our code performs a complex series of steps, working with Kentico's types in specific ways defined by our business requirements.

Unit tests might not be enough to guarantee that these interactions will operate how we expect at runtime, and integration tests might be more appropriate.

> You can read an example of what we might want in an integration test in my post _Kentico CMS Quick Tip: Integration Testing Roles_

> {% link wiredviews/kentico-cms-quick-tip-integration-testing-roles-h6i %}

However, there are some APIs that don't even work 😯 in an integration test scenario because they depend on a live running ASP.NET application, interacting with things like `HttpContext` and `Session`.

Fortunately there's a solution to this predicament 😅!

Let's look at an example.

---

## Testing `ShoppingService`

Kentico provides many service types behind interfaces that are registered with its own [Service Locator](https://en.wikipedia.org/wiki/Service_locator_pattern), `Service`, found in the `CMS.Core` namespace.

If we are using [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection), we could always mock these interfaces in our unit tests, but that doesn't fulfill the requirement of getting validation that the runtime interactions of multiple classes (and the database) will work as we expect.

Below we will look at running an integration test that works with `ShoppingService` 💰.

### Creating The Test Class

First, we create a [standard Kentico integration test](https://docs.kentico.com/k12sp/custom-development/writing-automated-tests/creating-integration-tests-with-a-connection-string), applying the correct `NUnit` test attributes and creating a test method:

```csharp
[TestFixture]
public class ShoppingServiceTests : IntegrationTests
{
    [Test]
    public void ShoppingService_AddItemsToCart_Will_Update_CartItems()
    {
        // ...
    }
}
```

> You can read more about setting up integration tests in Kentico in my post _Kentico 12: Design Patterns Part 8 - Setting Up Integration Tests_

> {% link seangwright/kentico-12-design-patterns-part-8-setting-up-integration-tests-14jg %}

---

### Our Initial Attempt

In our test method, we are going to work with `CMS.Ecommerce.ShoppingService` (through the `IShoppingService` interface), calling `AddItemToCart()`, which we would expect to update the database, inserting a row in `COM_ShoppingCartSKU` (for a new shopping cart).

Below we can see how we retrieve an `ShoppingService` instance from the `Service` service locator class and then immediately call `AddItemToCart()`.

```csharp
int skuId = 118;
int quantity = 1;

var shoppingService = Service.Resolve<IShoppingService>();

shoppingService.AddItemToCart(skuId, quantity);

var cart = shoppingService.GetCurrentShoppingCart();

cart.CartItems.Count.Should().Be(1);
```

This test will fail because this method requires that the execution context is a live running ASP.NET application, not a test application 😢.

The `AddItemToCart()` method assumes there is a user associated with the current request, whether that is an anonymous user or an authenticated one.

It also assumes there is a site that the request is being processed under. That site must have a valid Kentico license to allow for the E-Commerce functionality to be accessed 😵.

In our test method there is no "current request", so trying to access it for a user (by checking the `HttpContext.User.Identity`), or a site (by checking `HttpContext.Request.Url.Host`) will fail.

The above code will throw an exception at the line `shoppingService.AddItemToCart(skuId, quantity);` due to a foreign key constraint caused by the shopping cart not being persisted to the database correctly 🤦🏿‍♀️.

---

### Faking a Live Site

So, how can we "fake" a live ASP.NET application? By faking the parts that get used by the `ShoppingService`.

First, we assign a valid instance of `HttpContext` to `HttpContext.Current`, only filling in the values needed by the `ShoppingService.AddItemToCart()`:

```csharp
string siteUri = "https://localhost:44397";
string page = "/";

HttpContext.Current = new HttpContext(
    new HttpRequest(page, siteUri , ""), 
    new HttpResponse(null))
    {
        User = new ClaimsPrincipal(new ClaimsIdentity())
    };
```

The `siteUri` that is listed above has to be a domain that has a valid license in the CMS (in this case, `localhost`) 👍.

We also fill in the `HttpContext.User`, not with anything valid, but just ensuring nothing is `null` (this is due to the `ShoppingService` requiring this value to not be `null` internally).

Next, we use Kentico's `VirtualContext` static class to assign some values that would normally be populated by the current HTTP request.

Most of the `*Context` static classes source some data from `VirtualContext`, so setting values here will ensure they flow to the rest of Kentico's classes 🤯:

```csharp
string siteCodeName = "Sandbox";
string currentUserName = "sean@wiredviews.com";

VirtualContext.SetItem(VirtualContext.PARAM_SITENAME, siteCodeName);
VirtualContext.SetItem(VirtualContext.PARAM_USERNAME, currentUserName);
```

I assign a real username under the `VirtualContext.PARAM_USERNAME` key, so that when data is pulled from the database for the "current user", real information comes back. This user is also a valid Customer within the system.

I set the site name to match the site with a domain alias matching the `siteUri` I used above 🧐.

Now, we can write some code to validate our faked data is being passed around Kentico's libraries and giving us the state we desire.

Specifically, there should be an authenticated user in the system, and that user should be the same one I set with the `VirtualContext` above 🙂:

```csharp
bool isAuthenticated = AuthenticationHelper.IsAuthenticated();

isAuthenticated.Should().BeTrue();

var currentUser = MembershipContext.AuthenticatedUser;

currentUser.UserName.Should().Be(currentUserName);
```

Now that we have our simulated live ASP.NET context within our test method we can start making calls to `ShoppingService.AddItemToCart()`:

```csharp
int skuId1 = 118;
int skuId2 = 200;
int quantity = 1;

var shoppingService = Service.Resolve<IShoppingService>();

shoppingService.AddItemToCart(skuId1, quantity);

var cart = shoppingService.GetCurrentShoppingCart();

cart.CartItems.Count.Should().Be(1);

shoppingService.AddItemToCart(skuId2, quantity);

cart = shoppingService.GetCurrentShoppingCart();

cart.CartItems.Count.Should().Be(2);
```

Above, we add an item to the cart, ensure the `CartItems` count is `1`, and then add a different item, asserting the `CartItems` count is `2`.

If we were to debug this code, we'd see that the value returned by `shoppingService.GetCurrentShoppingCart()` would be a cart assigned to the site and Customer / User matching the username we populated in the `VirtualContext` 🤯.

This also means that if we skip deleting the cart when the test ends, and run it again, there will already be items in the cart from the previous test run - all of this data is coming from the database 🤓.

Pretty cool ⚡⚡👏!

---

## Pros and Cons

Faking a live environment can definitely be helpful, but its not easy. We have to know what dependencies the Kentico classes have - like `VirtualContext` and `HttpContext` - to ensure we fake the correct data.

Using a decompiler, or viewing the Kentico source code (if you have access to it), is really the only option here 🤷🏽‍♀️.

That said, it allows us to automate the interaction of many complex parts of our application - potentially scripting out an entire E-Commerce process from "Add To Cart", to "Payment", and finally to "Create Order" 😮.

If you've tried to test these processes before by stepping through the checkout process on the live site, manually clicking things until something succeeds or fails, an integration test like the one above might be a nice alternative 🤗.

It also can be helpful to see exactly how different combinations of Kentico's libraries interact together and what all the different APIs really do.

An integration test is like a mini-application where we can explore ideas, but without having to pay the cost of waiting for a site to start-up with every change we make 😊.

---

## Wrap Up

In this post we started out explaining the benefits of integration tests compared to unit tests, but realized that even integration tests can have issues when the code being tested needs to be run in an environment different than what the test simulates.

Some Kentico APIs expect a live ASP.NET request context to function correctly, which means if we want to test these we need to simulate them in our test.

Using `HttpContext.Current` and `VirtualContext`, we can simulate what Kentico's `ShoppingService` does when a real customer adds an item to their shopping cart 💪.

Figuring out these hidden dependencies can be difficult, but the reward is an integration test that both helps us better understand Kentico and verifies the behavior of our custom code that uses Kentico's APIs.

In the future I'd like to expand this `ShoppingService` integration test to include discounts, coupons, and creating an order from a shopping cart, so [follow me](https://dev.to/seangwright) to be alerted when I publish here on DEV 🤓.

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%3A%20Design%20Patterns)
- [Kentico CMS Quick Tips](https://dev.to/search?q=Kentico%20CMS%20Quick%20Tip)