From shesha-utils
Creates and scaffolds integration test projects for Shesha framework .NET applications. Sets up xUnit test infrastructure with NHibernate, database fixtures, test modules, and base classes. Detects whether Shesha.Testing NuGet package is available and adapts accordingly — using the package when present, or scaffolding local infrastructure when not. Use when the user asks to create, add, scaffold, implement, or set up integration tests, test projects, or test infrastructure for a Shesha project.
How this skill is triggered — by the user, by Claude, or both
Slash command
/shesha-utils:create-integration-testsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Scaffolds integration test infrastructure and creates integration tests for Shesha framework applications.
Scaffolds integration test infrastructure and creates integration tests for Shesha framework applications.
Before scaffolding, build a map of all source projects and their corresponding test projects.
# List all source projects (Domain, Application, etc.)
find backend/src/ -name "*.csproj" -type f
Identify the projects that contain testable code — typically Domain and Application projects (e.g., {Product}.{Module}.Application, {Product}.{Module}.Domain).
# Look for existing test projects
find backend/test/ -name "*Tests.csproj" -type f
# Look for existing test modules
grep -rn "SheshaModule" backend/test/ --include="*.cs" -l
# Look for existing test base classes
grep -rn "SheshaNhTestBase" backend/test/ --include="*.cs" -l
For each source project, check whether a corresponding *.Tests project already exists under backend/test/. The convention is {SourceProjectName}.Tests — for example:
| Source project | Expected test project |
|---|---|
{Product}.Common.Domain | {Product}.Common.Domain.Tests |
{Product}.Common.Application | {Product}.Common.Application.Tests |
{Product}.Foo.Domain | {Product}.Foo.Domain.Tests |
Classify each source project as:
*.Tests project existsIf ALL relevant source projects are covered: skip to Test Generation (Phase 2 in Workflow).
If some source projects are uncovered: proceed to Test Project Strategy before scaffolding.
Ideally, each source project that contains testable code should have its own dedicated test project. This keeps test dependencies focused and mirrors the solution's modular structure.
When uncovered source projects are found, ask the user before creating new test projects. Present the mapping and let them choose:
The following source projects do not have a corresponding test project:
{Product}.Foo.Domain(no{Product}.Foo.Domain.Testsfound){Product}.Common.Application(no{Product}.Common.Application.Testsfound)Options:
- Create dedicated test projects for each uncovered source project (recommended — mirrors solution structure)
- Add tests to an existing test project (e.g.,
{Product}.Common.Domain.Tests) — simpler but mixes concernsWhich approach would you prefer?
If the user chooses option 2, add the necessary project references to the existing test project's .csproj and ensure its test module DependsOn includes the modules from the newly covered source projects. Tests still follow the mirrored folder placement convention within whichever test project they land in.
If the user chooses option 1, scaffold each new test project using the steps below. New test projects can share infrastructure (fixtures, base classes) from an existing test project by adding a project reference to it, or scaffold their own — prefer sharing when a {Product}.Common.Tests or {Product}.Common.Domain.Tests project already provides SheshaNhTestBase and fixtures.
Before generating scaffolding code, determine which path to follow:
Shesha.Testing as a NuGet package or project referenceShesha.Testing namespace is resolvable (grep for Shesha.Testing in .csproj files)SheshaTestModuleHelper.ConfigureForTesting exists in referenced packagesIf Shesha.Testing IS available (framework version with the package): use the Framework Path. See references/framework-path.md.
If Shesha.Testing is NOT available (older framework version): use the Standalone Path. See references/standalone-path.md.
# Check in the .csproj files of the solution
grep -r "Shesha.Testing" --include="*.csproj" backend/
# Also check NuGet package cache
grep -r "SheshaTestModuleHelper" --include="*.cs" backend/
If neither grep returns results, use the Standalone Path.
backend/test/{Product}.Common.Domain.Tests/
├── {Product}CommonDomainTestModule.cs ← SheshaModule, test configuration
├── appsettings.Test.json ← DB connection + DBMS type
├── log4net.config ← Logging config
├── Fixtures/
│ ├── LocalSqlServerCollection.cs ← xUnit collection definition
│ └── (Standalone only: IDatabaseFixture.cs, LocalSqlServerFixture.cs)
├── DependencyInjection/
│ └── ServiceCollectionRegistrar.cs ← Identity bridge (standalone only)
├── (Standalone only infrastructure files)
└── {MirroredFolders}/ ← Mirrors source project structure
└── {Entity}_Tests.cs
Test classes must be placed in a folder structure that mirrors the source project being tested. This keeps tests organized and easy to locate.
To determine the correct folder, look at the namespace/folder of the class under test in the source project (e.g., backend/src/{Product}.Common.Domain/), then replicate that relative folder path inside the test project.
Example: If the source project has:
backend/src/{Product}.Common.Domain/
├── Enrollment/
│ ├── Applicant.cs
│ └── Application.cs
├── Assessments/
│ └── TestCase.cs
└── Scheduling/
└── Appointment.cs
Then the test project should mirror it:
backend/test/{Product}.Common.Domain.Tests/
├── Enrollment/
│ ├── Applicant_Tests.cs
│ └── Application_Tests.cs
├── Assessments/
│ └── TestCase_Tests.cs
└── Scheduling/
└── Appointment_Tests.cs
The namespace of each test class should reflect this folder path (e.g., {Product}.Common.Domain.Tests.Enrollment).
{SourceProjectName}.Tests — mirrors the source project name (e.g., {Product}.Common.Domain.Tests, {Product}.Foo.Application.Tests){SourceProjectName}TestModule with dots removed (e.g., {Product}CommonDomainTestModule){SourceProjectName}.Tests (infrastructure), {SourceProjectName}.Tests.{SubFolder} (test classes — matches mirrored folder path){ProductShort}-IntegrationTest (shared across all test projects — they use the same database)[Collection(LocalSqlServerCollection.Name)]
public class {Entity}_Tests : SheshaNhTestBase
{
private readonly IRepository<{Entity}, Guid> _repo;
private readonly IUnitOfWorkManager _uowManager;
public {Entity}_Tests(LocalSqlServerFixture fixture) : base(fixture)
{
_repo = Resolve<IRepository<{Entity}, Guid>>();
_uowManager = Resolve<IUnitOfWorkManager>();
}
[Fact]
public async Task GetAll_Should_Return_{Entities}()
{
var id = Guid.NewGuid();
// Arrange
using (var uow = _uowManager.Begin())
{
await _repo.InsertAsync(new {Entity} { Id = id, /* ... */ });
await uow.CompleteAsync();
}
// Act + Assert
using (var uow = _uowManager.Begin())
{
var all = await _repo.GetAllListAsync();
all.ShouldContain(e => e.Id == id);
await uow.CompleteAsync();
}
// Cleanup
using (var uow = _uowManager.Begin())
{
await _repo.DeleteAsync(id);
await uow.CompleteAsync();
}
}
}
using (var uow = _uowManager.Begin()) blockawait uow.CompleteAsync() to flush NHibernatetry/finally for cleanup when test data has relationshipsResolve<T>()Shouldly assertions (ShouldBe, ShouldNotBeNull, ShouldContain)$"{prefix}_{Guid.NewGuid():N}"[DependsOn(
typeof({Product}ApplicationModule), // Your app module
typeof({Product}Module), // Your domain module
typeof(AbpKernelModule),
typeof(AbpTestBaseModule),
typeof(AbpAspNetCoreModule),
typeof(SheshaApplicationModule),
typeof(SheshaNHibernateModule),
typeof(SheshaFrameworkModule),
typeof(SheshaWorkflowModule) // Required if any entities reference workflow types
)]
Important: Include SheshaWorkflowModule if domain entities reference any types from Shesha.Workflow (e.g. workflow-related entities, approval processes). Without it, NHibernate mapping fails with: The given key 'Shesha.Workflow, Version=...' was not present in the dictionary.
{
"DbmsType": "SQLServer",
"ConnectionStrings": {
"Default": "Data Source=.;Initial Catalog={ProductShort}-IntegrationTest;Integrated Security=True;TrustServerCertificate=True",
"TestDB": "Data Source=.;Initial Catalog={ProductShort}-IntegrationTest;Integrated Security=True;TrustServerCertificate=True"
}
}
Both Default and TestDB keys must be present and identical.
<PackageReference Include="Abp.Castle.Log4Net" Version="9.0.0" />
<PackageReference Include="Abp.TestBase" Version="9.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
<PackageReference Include="Shouldly" Version="4.2.1" />
<PackageReference Include="xunit" Version="2.6.3" />
<PackageReference Include="xunit.extensibility.execution" Version="2.6.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.5" />
Plus project references to the Application and Domain projects.
If the code under test sends notifications (e.g. approval workflows, notification services), you must register concrete INotificationChannelSender implementations in ServiceCollectionRegistrar. Without this, tests fail with: NotificationSender waiting for INotificationChannelSender.
// Add to ServiceCollectionRegistrar.Register() before WindsorRegistrationHelper call
services.AddTransient<INotificationChannelSender, EmailChannelSender>();
services.AddTransient<INotificationChannelSender, SmsChannelSender>();
Use concrete implementations (not mocks) for integration tests — the goal is to verify the full code path works end-to-end.
dotnet build all test projects to confirm infrastructure compilesThis phase runs whether infrastructure was just scaffolded or already existed. Repeat for each test project.
backend/src/*Domain*/**/*.cs, grep for entity base classesbackend/src/*Application*/**/*AppService.cs*_Tests.cs across all test projects, skip entities/services already tested{Entity}_Tests.cs per untested entity with at least a GetAll test. Place in the test project that corresponds to the entity's source project, in a folder that mirrors the entity's location (see Test File Placement){Service}_Tests.cs per untested service with custom methods. Place in the matching test project with mirrored folder structuredotnet build all test projects to confirm all tests compileAfter infrastructure is confirmed or scaffolded, always generate actual test classes. See references/test-generation.md for:
Key principle: every domain entity gets at least one test class verifying CRUD via repository. Every application service with custom business logic gets a test class exercising its methods.
For testing application services (not just repositories):
[Collection(LocalSqlServerCollection.Name)]
public class Dashboard_Tests : SheshaNhTestBase
{
private readonly DashboardAppService _dashboardService;
private readonly IRepository<TestCase, Guid> _testCaseRepo;
private readonly IUnitOfWorkManager _uowManager;
public Dashboard_Tests(LocalSqlServerFixture fixture) : base(fixture)
{
_dashboardService = Resolve<DashboardAppService>();
_testCaseRepo = Resolve<IRepository<TestCase, Guid>>();
_uowManager = Resolve<IUnitOfWorkManager>();
}
private string Unique(string prefix) => $"{prefix}_{Guid.NewGuid():N}";
[Fact]
public async Task GetKpis_Should_Return_Dashboard_Data()
{
Entity entity = null;
try
{
using (var uow = _uowManager.Begin())
{
entity = new Entity { Name = Unique("Test"), /* ... */ };
await _repo.InsertAsync(entity);
await uow.CompleteAsync();
}
using (var uow = _uowManager.Begin())
{
var result = await _dashboardService.GetKpis();
result.ShouldNotBeNull();
// assertions...
await uow.CompleteAsync();
}
}
finally
{
using (var uow = _uowManager.Begin())
{
if (entity != null) await _repo.DeleteAsync(entity);
await uow.CompleteAsync();
}
}
}
}
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub boxfusion/boxfusion-plugins --plugin shesha-utils