Write unit tests for scripts

From version 1.1.0 and later, the Sitecore Content Hub CLI lets you write and execute unit tests for your scripts using xUnit.net and NSubstitute.

Important

When using [Theory], [InlineData] is currently the only way of providing arguments to the test method.

This walkthrough describes how to:

Create a script

In your working directory, create a script with the name MyScript.csx:

RequestResponse
#load "./references/Action.csx"
/**------------ Include above to support intellisense on Content Hub types in editor ----------------**/
// Script Start

var entity = Context.Target as IEntity;
if (entity == null)
{
  MClient.Logger.Error("Entity is null.");
}

Create a test script

Unit test scripts are located in the unit-tests directory within the working directory and are expected to be named after the script that they are testing (for example, MyScript.csx). For that reason, it is important to have one test script for each script.

In the unit-tests directory, create a script matching the name of the script to test:

RequestResponse
#load "../references/UnitTest.csx"
/**------------ Include above to support intellisense on Content Hub types in editor ----------------**/
// Script Start

using System.Threading.Tasks;
using NSubstitute;
using Xunit;

[Fact]
public async Task Should_Log_Error_If_Entity_Is_Null()
{
  // Arrange
  var client = Substitute.For <IMClient>();

  var context = Substitute.For <IActionScriptContext>();
  context.Target.Returns(null);

  // Act
  await ScriptRunner.ExecuteAsync(client, context);

  // Assert
  client.Logger.Received(1).Error("Entity is null.");
}

The file structure should now be the following:

RequestResponse
[working folder]
├── lib
  └── ...
├── references
  ├── UnitTest.csx
  └── ...
├── unit-tests
  └── MyScript.csx <-- test script with the same name
├── MyScript.csx
├── omnisharp.json
├── references.json

Explanation of the test script code

  1. Create a named test method. The [Fact] attribute tells the test runner that this method is a unit test:

    RequestResponse
    [Fact]
    public async Task Should_Log_Error_If_Entity_Is_Null()
    
  2. Create mocks of the required objects that will be passed down to the actual script. This sets the context for different scenarios as well as mimic API calls that are being done through the MClient instance within the script. In this example, the Target property of the context is explicitly set to null:

    RequestResponse
    var client = Substitute.For <IMClient>();
    
    var context = Substitute.For <IActionScriptContext>();
    context.Target.Returns(null);
    
  3. Compiles and executes the related script (based on the file name) and passes the client and context instances down. When following the commonly used AAA (Arrange - Act - Assert) pattern, this call would be the Act section:

    RequestResponse
    await ScriptRunner.ExecuteAsync(client, context);
    
  4. Verify that the conditions of the test are met. In this case, an error message should have been logged.

    RequestResponse
    client.Logger.Received(1).Error("Entity is null.");
    

Run unit tests

You can either run all unit tests at once, or you can run a single unit test:

  • To run all unit tests, use the following code:

    RequestResponse
    ch-cli scripting unit-test (--folder <PATH_TO_WORKING_DIRECTORY> )
    
  • To run a single unit test, use the following code:

    RequestResponse
    ch-cli scripting unit-test (--<FOLDER_PATH_TO_WORKING_DIRECTORY> ) --name <TEST_FILE> 
    
    Example:
    ch-cli scripting unit-test --name <TEST_FILE> 
    

Do you have some feedback for us?

If you have suggestions for improving this article,