Unit testing custom macros
Unit testing your code is a great way to ensure that everything’s working properly under different scenarios. Creating custom macros is a popular way to extend Kentico’s capabilities, but as this code is placed within the content of your site and only evaluated when it’s rendered, how can you test the code?
First, you need to create a class in the test project to contain your custom macro methods. You can directly copy your class inheriting MacroMethodContainer used by the Kentico project:
using CMS;
using CMS.Helpers;
using CMS.MacroEngine;
using System;
using Testing;
[assembly: RegisterExtension(typeof(CustomMacroMethods), typeof(int))]
[assembly: RegisterExtension(typeof(CustomMacroMethods), typeof(MathNamespace))]
namespace Testing
{
public class CustomMacroMethods : MacroMethodContainer
{
[MacroMethod(typeof(int), "Returns the sum of two integers.", 2)]
[MacroMethodParam(0, "param1", typeof(int), "First digit to add.")]
[MacroMethodParam(1, "param2", typeof(int), "Second digit to add.")]
public static object Add(EvaluationContext context, params object[] parameters)
{
if (parameters.Length == 2)
{
int digit1 = ValidationHelper.GetInteger(parameters[0], 0);
int digit2 = ValidationHelper.GetInteger(parameters[1], 0);
return digit1 + digit2;
}
throw new NotSupportedException();
}
[MacroMethod(typeof(int), "Returns the difference of two integers.", 2)]
[MacroMethodParam(0, "param1", typeof(int), "First digit to subtract.")]
[MacroMethodParam(1, "param2", typeof(int), "Second digit to subtract.")]
public static object Subtract(EvaluationContext context, params object[] parameters)
{
if (parameters.Length == 2)
{
int digit1 = ValidationHelper.GetInteger(parameters[0], 0);
int digit2 = ValidationHelper.GetInteger(parameters[1], 0);
return digit1 - digit2;
}
throw new NotSupportedException();
}
}
}
Second, use a unit test scaffold following the NUnit testing pattern. For a refresher on unit tests with Kentico API, read through Creating automated test projects. Once ready, register your custom macro methods in the test’s SetUp method using MacroMethods.RegisterMethod, which is available in the CMS.MacroEngine namespace:
using CMS.Tests;
using NUnit.Framework;
using CMS.MacroEngine;
[TestFixture]
public class MyUnitTests : UnitTests
{
[SetUp]
public void MyUnitTestSetUp()
{
MacroMethods.RegisterMethod(new MacroMethod("Add", Testing.CustomMacroMethods.Add));
MacroMethods.RegisterMethod(new MacroMethod("Subtract", Testing.CustomMacroMethods.Subtract));
}
...
Third, create a test method for each macro method you’d like to test. Create a string that contains a macro expression just as you would in the Kentico interface, such as “{% Add(1,1) %}”, then use the GlobalResolver to resolve the macros in the string:
...
[Test]
public void Macro_Add()
{
int digit1 = 4, digit2 = 5;
string input = $"{{% {digit1}.Add({digit2}) %}}";
string expected = Convert.ToString(digit1 + digit2);
Assert.That(MacroContext.GlobalResolver.ResolveMacros(input), Is.EqualTo(expected));
}
[Test]
public void Macro_Subtract()
{
int digit1 = 2, digit2 = 3;
string input = $"{{% {digit1}.Subtract({digit2}) %}}";
string expected = Convert.ToString(digit1 - digit2);
Assert.That(MacroContext.GlobalResolver.ResolveMacros(input), Is.EqualTo(expected));
}
}
It’s important to note that certain contexts will not be available while unit testing your custom macros, such as SiteContext.CurrentSite.
That’s all there’s to it! Now you are able to test custom macro methods in the actual format they appear – within macro expressions. You will be able to catch issues, exceptions, or unexpected results in the code before it is deployed, resulting in more stable and more resilient production applications