Complete Unit Testing In Sitecore With Sitecore.Context And App_Config

Feels Like Magic

October 2, 2014

By Dan Cruickshank

Unit testing in Sitecore can be tricky. There are a lot of moving parts. And to truly be able to test, you need to somehow bring all of those parts into a test. That's exactly what I'm attempting do. - Execute unit tests **within a valid Sitecore context** - Load all current *App_Config/Include/* configs at runtime - Access to all APIs - Maintain to additional config files - No scripting involved At high-level we'll accomplish this by: - Renaming your *web.config* to *app.config* - Including all config files in your **IntegrationTests** project as **Links** - Run a line of a voodoo code that dynamically sets Sitecore's current directory Let's do this. It's mostly screenshots and code samples anyways.

Create A New Test Project

Create a new project in Visual Studio for the tests. Make sure it's a standard Class Library. Call it what you want, I like **Fishtank.IntegrationTests**.

Create Your App.Config

Steps: - Copy & paste your *web.config* from your website into **IntegrationTests** project. - Rename it *app.config*. - Check the *app.config*'s properties (alt+enter). Ensure that **Copy to Output Directory** is set to *Copy Always*. A Class Library uses an app.config instead of a web.config. Hopefully, you're following best-practices and modifying your web.config indirectly via */App_Config/Include/* As rule, we want to make sure every config we drop in here is set to **Copy**.

Recreate The App_Config Folder Structure

We'll create a folder structure inside **Fishtank.IntegrationTests**, mimicking *\Website\App_Config*:
- App_Config
    - Include
    - Prefetch
    - Security

Add Config Files As A Link

Now here comes a wee bit of magic. We need all of our config files in our **IntegrationTests** project but don't want to maintain two copies of them. For this we use **Add As Link**: - Right-click *App_Config* inside to the **IntegrationTests** project - Add > Existing Item... - Navigate to file explorer to *Website\App_Config* - Use an **asterisk** to show all the config files.
- Use *Shift* to highlight all files (not folders) - Note the down arrow beside "Add" > click > Select **Add As Link** Repeat these step with the *App_Config/Include*, *App_Config/Prefetch* & *App_Config/Security* folders respectively.

Set All Linked Configs To Copy

One final step, super important. Highlight all the config files in each folder under *App_Config* change **Copy to Output Directory** setting to *Copy if newer*. Be sure to **Save All** on the solution after doing this.

All Configs Set As Linked

Notice all files have been added. They have a special icon indicating that they're **linked**.

Add NUnit Via NuGet

NUnit is my test runner of choice. Feel free to divert from the step is you have your own favorite. Here are the steps. - In your **Integration** project, right-click **References** - Click **Manage NuGet Packages...**
- Search for **nunit** using the search box. Add it. - Rock and roll.

Add Sitecore DLL References

In your **Integration** project, under **References**, add a local reference to *Sitecore.Kernel.dll* & *Sitecore.Nexus.dll*. Make sure **Copy Local** is set to *True* for in the properties.

Change Sitecore's Root Path During Tests

This step is bit of a dark art. We're make a class that executes before any test(s) are run. It reassigns Sitecore's file system to run from the **IntegrationTests** project build folder: - Create a new Class called *TestSetupFixture.cs* in the **IntegrationTests** project.
- Copy & paste the below code. - See inline comments for a brief explanation **TestSetupFixture.cs**

using System;
using System.IO;
using NUnit.Framework;
using Sitecore;
using Sitecore.Configuration;
using Sitecore.Globalization;
using Sitecore.SecurityModel;

namespace Fishtank.IntegrationTests
{
    // In NUnit, this ensures it will run before any/all tests are executed
    [SetUpFixture]
    public class TestSetupFixture
    {
        public static SecurityDisabler _disabler;


        [SetUp]
        public void SetupTest()
        {
            try
            {
                // This grounds Sitecore in the current directory so when 
                // Sitecore.IO.FileUtil.MapPath runs, it can find the files.                
                State.HttpRuntime.AppDomainAppPath = Directory.GetCurrentDirectory();

                // This static.  Allows it live, avoiding garbage collection
                _disabler = new SecurityDisabler();


                // If you need to run pipelines do it hear.
                //CorePipeline.Run("initialize", new PipelineArgs());

                // Set any properties you need in content
                Context.SetLanguage(Language.Parse("en"), false);
            }

            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                throw;
            }
        }
    }
}

If you don't use NUnit, you'll have to find an equivalent methodology. Or simply run the above code manually at the start of your tests.

Create A Unit Test To Prove It Works

Now we'll create a test to prove that we're up and running. Let's call it *SimpleTests.cs*. Decorate the class as a *[TestFixture]* and the test method with *[Test]*. This test will prove the following: - The configs */App_Config/Include* are being processed. The information we're looking for is coming from */App_Config/Include/SiteDefinition.getfishtank.ca.config* - The Sitecore Context does exist - Context-specific values can be set, retrieved - Databases are active

using NUnit.Framework;

namespace Fishtank.IntegrationTests
{
    [TestFixture]
    public class SimpleTests
    {
        [Test]
        public void ShouldFindTheHomeNode()
        {
            // Get getfishtank is declared under:
            // /App_Config/Include/SiteDefinition.getfishtank.ca.config
            Sitecore.Context.SetActiveSite("getfishtank");
                        
            // Pull the start path of the site
            string startPath = Sitecore.Context.Site.StartPath;
            
            // Pull the database name
            string databaseName = Sitecore.Context.Site.Database.Name;

            // Load the web database, and get item
            var db = Sitecore.Data.Database.GetDatabase("web");
            var item = db.GetItem("/sitecore/content/fishtank/home");           
           
            
            // Found the home node
            Assert.That(item, Is.Not.Null);

            // Paths of the home items match
            Assert.That(startPath.ToLower(), Is.EqualTo(item.Paths.FullPath.ToLower()));
            
            // Database name pulled from context matches too 
            Assert.That(databaseName, Is.EqualTo(db.Name));
        }
    }
}

Almost there!

Proof That It Worked

For proof, this is the best I can reasonably do.
An all encompassing screenshot showing: - Visual Studio - Open *SimpleTest.cs* test file - Open site defintion file, */App_Config/Include/SiteDefinition.getfishtank.ca.config* - NUnit test runner window showing a **passed test** - **Properties** window showing that the linked config resides in */App_Config/Include/*.

Potential Issues

If your file system paths in your *web.config* are absolute, they may need adjusting. Prefixing paths with a dot *./App_Config/* is all that's usually required. Definitely beware of the paths. Also - be sure to **Rebuild** your **IntegrationTests** project in Visual Studio before you run your tests. The **Rebuild** copies your *App_Config* folder to the tests *bin* folder. For some reason, running tests using NUnit doesn't copy them.
If you this is your problem, you'll see these errors:
TestFixtureSetUp failed in TestSetupFixture
Exception doesn't have a stacktrace
Could not find a part of the path 'C:\getfishtank\Fishtank.IntegrationTests\bin\Debug\app_config\prototypes.config'.

Closing Thoughts

To recap fundamental principles here: - Renamed your *web.config* to *app.config* - Include all config files in your **IntegrationTests** project as **Links** - Run a line of a voodoo code that dynamically sets Sitecore's current directory This looks like a bit of work but once you understand the steps, it's quick process. And being able to test with a context and all your configs is defintely worth the effort. Technically, we could deliniate between integration tests and unit tests. Connecting to Sitecore makes this approach integration testing as opposed to unit testing. Unit testing has no external dependency. That distinction may or may not be relevant to you. If you have any questions or comments please leave them below or reach me on twitter at [@dancruickshank](https://twitter.com/dancruickshank). I'm happy to help. This post was authored using [Markdown for Sitecore](/blog/module-markdown-for-sitecore).
Dan Headshot

Dan Cruickshank

President | Sitecore MVP x 11

Dan is the founder of Fishtank. He's a multi-time Sitecore MVP and Coveo MVP award winner. Outside of technology, he is widely considered to be a top 3 father (routinely receiving "Father of the Year" accolades from his family) and past his prime on the basketball court.