Kentico CMS Quick Tip: Integration Testing Roles
Tags: kentico, dotnet, testing, csharp
Published: 2019-07-29 14:01:09

---
title: Kentico CMS Quick Tip: Integration Testing Roles
published: true
description: Learn how to ensure the Roles in our Kentico MVC application matches what's configured in the CMS database.
tags: kentico, dotnet, testing, csharp
series: Kentico Quick Tips
---

![](https://thepracticaldev.s3.amazonaws.com/i/3m03fz5cuocblxc2hpu6.jpg)
<figcaption>Photo by <a href="https://unsplash.com/@jasebloor">Jase Bloor</a> on <a href="https://unsplash.com">Unsplash</a></figcaption>

## Know Your Roles! 🧐

When reviewing our Kentico 12 MVC applications we probably have some lines of code that look something like the following:

```csharp
int userId = ...

if (userManager.IsInRole(userId, "Manager"))
{
    IEnumerable<string> protectedData = GetTheData();

    return protectedData;
}
else
{
    return Enumerable.Empty<string>();
}
```

For this code to function correctly, when your site is running, the `"Manager"` role must exist in the database and be assigned to the right users.

How do we know, at any given time, this is true? 😕

What happens when we make changes to roles in our code or the database (either adding, removing, or renaming them)? 😟

Is there a way to easily verify all the roles in our code match the roles defined in the CMS?

## Avoid Scattered Strings

My first recommendation would be to avoid using "Scattered Strings".

How many places throughout our code do we have lines like these?

```csharp
if (userManager.IsInRole(userId, "Manager")) { ... }
```
```csharp
userManager.AddToRole(userId, "SpecialUser"));
```
```csharp
userManager.RemoveFromRole(userId, "Admin"));
```

Those role names can quickly become scattered throughout our application, which makes them hard to keep track of and update. Typos can be easy to miss, even with code reviews. 😣

These aren't [Magic Strings](https://en.wikipedia.org/wiki/Magic_string) because their purpose is clear - but it is a value that the compiler cannot help us with since `string` values don't have a business meaning.

A typo'd `string` is the same as a `string` with the correct value as far as the compiler is concerned.

> Primitive types can be a poor choice for storing values that have important business meaning. If you find yourself running into issues with Scattered Strings in your code base you might have a case of [Primitive Obsession](http://wiki.c2.com/?PrimitiveObsession)

We can instead replace them with a static Role class that contains all of our roles.

```csharp
public static class UserRoles
{
    public const string MANAGER = nameof(MANAGER);
    public const string SPECIAL_USER = nameof(SPECIAL_USER);
    public const string ADMIN = nameof(ADMIN);
}
```

> Using the [nameof() operator](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/nameof) helps ensure the name of the constant and its value are never out of sync.

Now we can use this class wherever we'd normally use our role name strings. 😉

```csharp
if (userManager.IsInRole(userId, UserRoles.MANAGER)) { ... }
```

Avoiding Scattered Strings helps reduce typos and makes changes easier by relying on the C# language and Visual Studio refactoring tools when adding, removing, or updating a role name. 😀

But, it doesn't prevent us from having a role defined in the code that doesn't exist in the database. 😯

---

## Write Integration Tests

The best way to check that the database always matches our code's expectations is to write, and then run, some integration tests.

> If you haven't written Integration Tests for your Kentico sites before, checkout my post "Setting Up Integration Tests":

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

So what might our integration test look like?

We could query the database for each one of our roles and make sure it's not `null`:

```csharp
[TestFixture]
public class UserRolesTests : IntegrationTests
{
    private readonly int siteId = 1;

    [Test]
    public void UserRoles_Will_Be_In_The_Database()
    {    
        RoleInfo managerRole = RoleInfoProvider
            .GetRoleInfo(UserRoles.MANAGER, siteId);

        RoleInfo specialUserRole = RoleInfoProvider
            .GetRoleInfo(UserRoles.SPECIAL_USER, siteId);

        RoleInfo adminRole = RoleInfoProvider
            .GetRoleInfo(UserRoles.ADMIN, siteId);

        managerRole.Should().NotBeNull();
        specialUserRole.Should().NotBeNull();
        adminRole.Should().NotBeNull();
    }
}
```

> I'm using [FluentAssertions](https://fluentassertions.com/) to give me access to the Behavior Driven Design (BDD) style `.Should()` extension methods.

This does the trick! 👍

If any of the roles we are querying are missing from the database, then our integration test will fail. 👏

However, it seems easy enough to accidentally leave out a role in the above test, especially if we have a large number of roles in our application. 💣

That role querying and asserting also looks to be doing the same thing over and over.

Let's try again:

```csharp
[TestFixture]
public class UserRolesTests : IntegrationTests
{
    private readonly int siteId = 1;

    [Test]
    public void UserRoles_Will_Be_In_The_Database()
    {
        List<string> appRoleNames = typeof(UserRoles)
            .GetFields(BindingFlags.Public | BindingFlags.Static)
            .Select(f => f.Name)
            .ToList();

        List<string> roleNames = RoleInfoProvider.GetRoles()
            .WhereEquals(nameof(RoleInfo.SiteID), siteId)
            .WhereIn(nameof(RoleInfo.RoleName), userRoleNames)
            .Column(nameof(RoleInfo.RoleName))
            .AsEnumerable()
            .Select(r => r.RoleName)
            .ToList();

        roleNames.Should().BeEquivalentTo(appRoleNames);
    }
}
```

With this test we use reflection to gather up all the names of the fields of the `UserRoles` class. 🧠

We use the `RoleInfoProvider.GetRoles()` method, combined with the powerful [ObjectQuery](https://docs.kentico.com/k12sp/custom-development/retrieving-database-data-using-objectquery-api) extension methods to retrieve the same set of roles from the database. 💪

We then assert that the two collections of strings match.

Nice! 🎉

> Notice how we use the `nameof()` operator in our `ObjectQuery` as well. I recommend you use it instead of typing out the string names of the database columns to avoid the same Scattered String issues we saw about with Roles.

> Since the convention in Kentico is to name class property names the same as database column names, the `nameof()` operator is a great way to avoid typos. 🤗

---

## Summary

There's always going to be a disconnect between data sources and application code. Our applications are often designed to be stateless to allow scaling, while our data sources are where we store all the shared application state.

When we need to have logic in our application based on that state we encode values from the data source, like role names, into our code.

Integration tests are a great way to ensure that the expectations of our application match what the data source will give us. 😎

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)