migration-unit-testing
Testing strategy and patterns for validating modernized and migrated software.
Install
mkdir -p .claude/skills/migration-unit-testing && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/15876" && unzip -o skill.zip -d .claude/skills/migration-unit-testing && rm skill.zipInstalls to .claude/skills/migration-unit-testing
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Unit testing patterns for validating migrated applications. **Use when:** Creating tests to verify migration correctness and prevent regressions. **Triggers on:** Test creation requests, validation phase, post-migration verification. **Covers:** xUnit/NUnit for .NET, JUnit 5 for Java, mocking strategies, test organization patterns.Key capabilities
- →Create tests for business logic
- →Validate data access operations
- →Test API endpoint contracts
- →Implement mocking for external dependencies
- →Establish test coverage baselines
How it works
The skill outlines strategies and provides code examples for creating unit tests for migrated applications, focusing on business logic, data access, and API contracts.
Inputs & outputs
When to use migration-unit-testing
- →Create tests for migration
- →Validate business logic
- →Implement equivalence testing
- →Set up mocking
About this skill
Migration Unit Testing Skill
Use this skill when creating unit tests to validate migrated applications work correctly after modernization.
When to Use This Skill
- Creating tests to validate migration correctness
- Building test suites for migrated applications of any stack (
.NET,Java,Python,Node.js,PHP,Ruby,Go, etc.). This skill ships worked examples for .NET and Java; adapt the same patterns to other stacks using their idiomatic test frameworks (pytest for Python, jest/vitest for Node, phpunit for PHP, rspec for Ruby, testing package for Go, etc.). - Implementing equivalence testing (old vs new behavior)
- Setting up mocking for external dependencies
- Creating regression tests for business logic
- Establishing test coverage baselines
Testing Strategy for Migrated Applications
Priority Order
- Business Logic - Critical calculations, validations, workflows
- Data Access - Repository operations, query correctness
- API Endpoints - Request/response contracts, status codes
- Authentication/Authorization - Security flows
- Integrations - External service interactions
- UI Components - View models, presentation logic
Coverage Goals
| Code Area | Minimum Coverage | Target Coverage |
|---|---|---|
| Business logic | 80% | 90%+ |
| API controllers | 70% | 85% |
| Data access | 60% | 80% |
| Utilities/helpers | 70% | 90% |
.NET Testing Patterns (xUnit)
Project Setup
<!-- Tests.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<IsPackable>false</IsPackable>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="xunit" Version="2.6.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.4" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="10.0.0" />
</ItemGroup>
</Project>
Test Naming Convention
MethodName_Scenario_ExpectedBehavior
Examples:
GetUser_WithValidId_ReturnsUserCreateOrder_WithInvalidItems_ThrowsValidationExceptionCalculateDiscount_WhenTotalExceeds100_Returns10Percent
Service Layer Test
public class UserServiceTests
{
private readonly Mock<IUserRepository> _repositoryMock;
private readonly Mock<ILogger<UserService>> _loggerMock;
private readonly UserService _sut; // System Under Test
public UserServiceTests()
{
_repositoryMock = new Mock<IUserRepository>();
_loggerMock = new Mock<ILogger<UserService>>();
_sut = new UserService(_repositoryMock.Object, _loggerMock.Object);
}
[Fact]
public async Task GetByIdAsync_WithExistingUser_ReturnsUser()
{
// Arrange
var expectedUser = new User { Id = 1, Name = "John Doe", Email = "[email protected]" };
_repositoryMock
.Setup(r => r.GetByIdAsync(1))
.ReturnsAsync(expectedUser);
// Act
var result = await _sut.GetByIdAsync(1);
// Assert
result.Should().NotBeNull();
result.Should().BeEquivalentTo(expectedUser);
}
[Fact]
public async Task GetByIdAsync_WithNonExistingUser_ReturnsNull()
{
// Arrange
_repositoryMock
.Setup(r => r.GetByIdAsync(It.IsAny<int>()))
.ReturnsAsync((User?)null);
// Act
var result = await _sut.GetByIdAsync(999);
// Assert
result.Should().BeNull();
}
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
public async Task CreateAsync_WithInvalidName_ThrowsArgumentException(string? invalidName)
{
// Arrange
var dto = new CreateUserDto(invalidName!, "[email protected]");
// Act
var act = () => _sut.CreateAsync(dto);
// Assert
await act.Should().ThrowAsync<ArgumentException>()
.WithMessage("*name*");
}
}
Controller Integration Test
public class UsersControllerTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly HttpClient _client;
private readonly WebApplicationFactory<Program> _factory;
public UsersControllerTests(WebApplicationFactory<Program> factory)
{
_factory = factory.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
{
// Replace real DB with in-memory
var descriptor = services.SingleOrDefault(
d => d.ServiceType == typeof(DbContextOptions<AppDbContext>));
if (descriptor != null)
services.Remove(descriptor);
services.AddDbContext<AppDbContext>(options =>
options.UseInMemoryDatabase("TestDb"));
});
});
_client = _factory.CreateClient();
}
[Fact]
public async Task GetUsers_ReturnsSuccessAndCorrectContentType()
{
// Act
var response = await _client.GetAsync("/api/users");
// Assert
response.EnsureSuccessStatusCode();
response.Content.Headers.ContentType?.MediaType.Should().Be("application/json");
}
[Fact]
public async Task GetUser_WithInvalidId_ReturnsNotFound()
{
// Act
var response = await _client.GetAsync("/api/users/99999");
// Assert
response.StatusCode.Should().Be(HttpStatusCode.NotFound);
}
[Fact]
public async Task CreateUser_WithValidData_ReturnsCreatedWithLocation()
{
// Arrange
var newUser = new { Name = "Jane Doe", Email = "[email protected]" };
var content = new StringContent(
JsonSerializer.Serialize(newUser),
Encoding.UTF8,
"application/json");
// Act
var response = await _client.PostAsync("/api/users", content);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.Created);
response.Headers.Location.Should().NotBeNull();
}
}
Database Test with In-Memory Provider
public class UserRepositoryTests : IDisposable
{
private readonly AppDbContext _context;
private readonly UserRepository _sut;
public UserRepositoryTests()
{
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
_context = new AppDbContext(options);
_sut = new UserRepository(_context);
}
[Fact]
public async Task AddAsync_AddsUserToDatabase()
{
// Arrange
var user = new User { Name = "Test User", Email = "[email protected]" };
// Act
await _sut.AddAsync(user);
await _context.SaveChangesAsync();
// Assert
var savedUser = await _context.Users.FirstOrDefaultAsync(u => u.Email == "[email protected]");
savedUser.Should().NotBeNull();
savedUser!.Name.Should().Be("Test User");
}
public void Dispose() => _context.Dispose();
}
Java Testing Patterns (JUnit 5)
Project Setup (pom.xml)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Service Layer Test
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
@DisplayName("Should return user when valid ID provided")
void findById_WithValidId_ReturnsUser() {
// Given
User expectedUser = new User(1L, "John Doe", "[email protected]");
when(userRepository.findById(1L)).thenReturn(Optional.of(expectedUser));
// When
Optional<User> result = userService.findById(1L);
// Then
assertThat(result)
.isPresent()
.hasValueSatisfying(user -> {
assertThat(user.getName()).isEqualTo("John Doe");
assertThat(user.getEmail()).isEqualTo("[email protected]");
});
}
@Test
@DisplayName("Should return empty when user not found")
void findById_WithNonExistingId_ReturnsEmpty() {
// Given
when(userRepository.findById(anyLong())).thenReturn(Optional.empty());
// When
Optional<User> result = userService.findById(999L);
// Then
assertThat(result).isEmpty();
}
@ParameterizedTest
@NullAndEmptySource
@ValueSource(strings = {" ", " "})
@DisplayName("Should throw exception for invalid name")
void create_WithInvalidName_ThrowsException(String invalidName) {
// Given
CreateUserDto dto = new CreateUserDto(invalidName, "[email protected]");
// When/Then
assertThatThrownBy(() -> userService.create(dto))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContain
---
*Content truncated.*
When not to use it
- →When testing UI components as a top priority
- →When not setting up mocking for external dependencies
- →When not establishing test coverage baselines
Limitations
- →Requires xUnit for .NET or JUnit 5 for Java
- →Requires mocking strategies for external dependencies
- →Requires test coverage goals to be defined
How it compares
This skill provides specific patterns and a priority order for unit testing migrated applications, ensuring critical components are validated first, unlike general unit testing approaches.
Compared to similar skills
migration-unit-testing side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| migration-unit-testing (this skill) | 0 | 5mo | Review | Intermediate |
| unit-testing | 3 | 3mo | No flags | Beginner |
| springboot-verification | 4 | 4mo | Review | Intermediate |
| dotnet-dev | 1 | 6mo | Review | Beginner |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
unit-testing
TencentBlueKing
单元测试编写指南,涵盖 JUnit5/MockK 使用、测试命名规范、Mock 技巧、测试覆盖率要求、TDD 实践。当用户编写单元测试、Mock 依赖、提高测试覆盖率或进行测试驱动开发时使用。
springboot-verification
affaan-m
Verification loop for Spring Boot projects: build, static analysis, tests with coverage, security scans, and diff review before release or PR.
dotnet-dev
GitTools
Expert guidance for .NET development in this repository. Use this skill for building, testing, debugging, and understanding project structure, coding conventions, dependency injection patterns, and testing practices.
mocking
comeredon
Mockito mocking patterns for isolating units under test. Use when testing classes with external dependencies like databases, files, or APIs.
code-checklist
comeredon
Critical code requirements checklist derived from actual build failures. Use before committing code or when troubleshooting compilation errors.
code-review
jason-kerney
>