Write automated tests
Test automation is an important part of every development project and is essential for agile workflows. Automated tests help you improve productivity, reduce the testing phase of the development cycle, and increase code predictability and quality.
Xperience by Kentico provides the CMS.Tests library, which simplifies writing automated tests for code that uses the Xperience API. The library contains base classes for unit tests and integration tests, as well as helper classes for faking Info and Provider objects. You can obtain the library by installing the Kentico.Xperience.Core.Tests NuGet package into your test projects.
When developing custom functionality for Xperience projects, we recommend that you create projects with automated tests to cover the given code.
Supported testing framework
All functionality in the CMS.Tests library is compatible with the NUnit testing framework.
The package does not include a test runner or a mocking library. For detailed test project setup requirements, see Set up test projects.
For test doubles (fakes) of service dependencies, choose any mocking library that fits your project (for example Moq, NSubstitute, or FakeItEasy), or use hand-written fakes and stubs.
Choose a testing approach
Xperience provides several base classes for automated tests, each suited to different scenarios. Choose based on how your code interacts with the Xperience API and whether it requires database access.
|
Approach |
Advantages |
Drawbacks |
When to use |
|
Unit tests with faked data ( |
Fast execution, no database needed, in-memory faking of Info and Provider objects via |
Cannot test real database behavior, requires manual faking of all data dependencies, cannot fake content items or website channel pages |
Testing services, validators, or business logic that interacts with the Xperience API through Info and Provider classes. This should be the default for most tests. |
|
Integration tests ( |
Tests against a real database, verifies actual query behavior, supports content items and pages |
Significantly slower, requires a configured database, manual cleanup of test data |
Testing complex queries or behavior that depends on database-specific features where faked providers are insufficient. |
|
Isolated integration tests ( |
Automatic database creation and cleanup, no risk of polluting shared databases |
Slowest of all approaches, requires SQL Server Express LocalDB (or alternative configuration) |
Testing code that creates, updates, or deletes data when rollback or cleanup is complex. |
Write most of your tests as unit tests with faked data. Reserve integration tests and isolated integration tests for scenarios where you need to verify real database behavior. This balance maximizes test speed while maintaining coverage of critical paths.
Code that retrieves content items and website channel pages requires a separate set of approaches. See Test code that retrieves content.
API differences in test code
By default, all Xperience API calls executed within tests that inherit from the CMS.Tests base classes run without operations that are unnecessary in a testing context. The system disables:
- Event logging
- Multi-instance synchronization tasks
- Asynchronous action dispatch
- Email sending
These operations are typically not relevant for test results and unnecessarily reduce test performance.
To enable these operations in your tests, wrap the relevant code in a CMSActionContext block with the corresponding properties set to true.
using CMS.Base;
using (new CMSActionContext { SendEmails = true })
{
// Test execution with email sending enabled
}
Best practices for testable code
To write code that is easy to test:
- Use dependency injection – Inject interfaces rather than depending on concrete classes. This allows you to substitute real implementations with test doubles. See Dependency injection.
- Separate concerns – Keep business logic in dedicated services rather than in controllers or event handlers.
- Keep methods focused – Small methods with a single responsibility are easier to test in isolation.