🎯

tasks-test-generation

🎯Skill

from duc01226/easyplatform

VibeIndex|
What it does

Autonomously generates comprehensive unit and integration tests for backend and frontend code using structured templates and best practices.

πŸ“¦

Part of

duc01226/easyplatform(87 items)

tasks-test-generation

Installation

πŸ“‹ No install commands found in docs. Showing default command. Check GitHub for actual instructions.
Quick InstallInstall with npx
npx skills add duc01226/easyplatform --skill tasks-test-generation
6Installs
3
-
Last UpdatedJan 23, 2026

Skill Details

SKILL.md

Use when creating or enhancing unit tests, integration tests, or defining test strategies for backend and frontend code.

Overview

> Skill Variant: Use this skill for autonomous test generation with structured templates. For interactive test writing with user feedback, use test-generation instead.

# Test Generation Workflow

When to Use This Skill

  • Creating unit tests for new code
  • Adding tests for bug fixes
  • Integration test development
  • Test coverage improvement

Pre-Flight Checklist

  • [ ] Identify code to test (command, query, entity, component)
  • [ ] Find existing test patterns: grep "Test.{Feature}" --include=".cs"
  • [ ] Determine test type (unit, integration, e2e)
  • [ ] Identify dependencies to mock

File Locations

Backend Tests

```

tests/

└── {Service}.Tests/

β”œβ”€β”€ UnitTests/

β”‚ β”œβ”€β”€ Commands/

β”‚ β”‚ └── Save{Entity}CommandTests.cs

β”‚ β”œβ”€β”€ Queries/

β”‚ β”‚ └── Get{Entity}ListQueryTests.cs

β”‚ └── Entities/

β”‚ └── {Entity}Tests.cs

└── IntegrationTests/

└── {Feature}IntegrationTests.cs

```

Frontend Tests

```

src/Frontend/apps/{app}/src/app/

└── features/

└── {feature}/

β”œβ”€β”€ {feature}.component.spec.ts

└── {feature}.store.spec.ts

```

Pattern 1: Command Handler Unit Test

```csharp

public class SaveEmployeeCommandTests

{

private readonly Mock> _employeeRepoMock;

private readonly Mock _contextMock;

private readonly SaveEmployeeCommandHandler _handler;

public SaveEmployeeCommandTests()

{

_employeeRepoMock = new Mock>();

_contextMock = new Mock();

// Setup default context

var requestContext = new Mock();

requestContext.Setup(x => x.UserId()).Returns("test-user-id");

requestContext.Setup(x => x.CurrentCompanyId()).Returns("test-company-id");

_contextMock.Setup(x => x.Current).Returns(requestContext.Object);

_handler = new SaveEmployeeCommandHandler(

Mock.Of(),

Mock.Of(),

Mock.Of(),

Mock.Of(),

_employeeRepoMock.Object

);

}

[Fact]

public async Task HandleAsync_CreateEmployee_ReturnsNewEmployee()

{

// Arrange

var command = new SaveEmployeeCommand

{

Name = "John Doe",

Email = "john@example.com"

};

_employeeRepoMock

.Setup(x => x.CreateAsync(It.IsAny(), It.IsAny()))

.ReturnsAsync((Employee e, CancellationToken _) => e);

// Act

var result = await _handler.HandleAsync(command, CancellationToken.None);

// Assert

Assert.NotNull(result.Employee);

Assert.Equal("John Doe", result.Employee.Name);

_employeeRepoMock.Verify(x => x.CreateAsync(

It.Is(e => e.Name == "John Doe"),

It.IsAny()), Times.Once);

}

[Fact]

public async Task HandleAsync_UpdateEmployee_UpdatesExisting()

{

// Arrange

var existingEmployee = new Employee { Id = "emp-1", Name = "Old Name" };

var command = new SaveEmployeeCommand

{

Id = "emp-1",

Name = "New Name"

};

_employeeRepoMock

.Setup(x => x.GetByIdAsync("emp-1", It.IsAny()))

.ReturnsAsync(existingEmployee);

_employeeRepoMock

.Setup(x => x.UpdateAsync(It.IsAny(), It.IsAny()))

.ReturnsAsync((Employee e, CancellationToken _) => e);

// Act

var result = await _handler.HandleAsync(command, CancellationToken.None);

// Assert

Assert.Equal("New Name", result.Employee.Name);

_employeeRepoMock.Verify(x => x.UpdateAsync(

It.Is(e => e.Name == "New Name"),

It.IsAny()), Times.Once);

}

[Fact]

public async Task HandleAsync_InvalidCommand_ReturnsValidationError()

{

// Arrange

var command = new SaveEmployeeCommand

{

Name = "" // Invalid: empty name

};

// Act & Assert

var result = command.Validate();

Assert.False(result.IsValid);

Assert.Contains(result.Errors, e => e.Contains("Name"));

}

}

```

Pattern 2: Query Handler Unit Test

```csharp

public class GetEmployeeListQueryTests

{

private readonly Mock> _repoMock;

private readonly GetEmployeeListQueryHandler _handler;

[Fact]

public async Task HandleAsync_WithFilters_ReturnsFilteredResults()

{

// Arrange

var employees = new List

{

new() { Id = "1", Name = "Active", Status = EmployeeStatus.Active },

new() { Id = "2", Name = "Inactive", Status = EmployeeStatus.Inactive }

};

_repoMock.Setup(x => x.CountAsync(It.IsAny>>(), It.IsAny()))

.ReturnsAsync(1);

_repoMock.Setup(x => x.GetAllAsync(It.IsAny, IQueryable>>(), It.IsAny(), It.IsAny>[]>()))

.ReturnsAsync(employees.Where(e => e.Status == EmployeeStatus.Active).ToList());

var query = new GetEmployeeListQuery

{

Statuses = [EmployeeStatus.Active],

SkipCount = 0,

MaxResultCount = 10

};

// Act

var result = await _handler.HandleAsync(query, CancellationToken.None);

// Assert

Assert.Single(result.Items);

Assert.Equal("Active", result.Items[0].Name);

}

}

```

Pattern 3: Entity Validation Test

```csharp

public class EmployeeEntityTests

{

[Fact]

public void UniqueExpr_ReturnsCorrectExpression()

{

// Arrange

var employees = new List

{

new() { CompanyId = "c1", UserId = "u1" },

new() { CompanyId = "c1", UserId = "u2" },

new() { CompanyId = "c2", UserId = "u1" }

}.AsQueryable();

// Act

var expr = Employee.UniqueExpr("c1", "u1");

var result = employees.Where(expr).ToList();

// Assert

Assert.Single(result);

Assert.Equal("u1", result[0].UserId);

}

[Fact]

public async Task ValidateAsync_DuplicateCode_ReturnsError()

{

// Arrange

var repoMock = new Mock>();

repoMock.Setup(x => x.AnyAsync(It.IsAny>>(), It.IsAny()))

.ReturnsAsync(true); // Duplicate exists

var employee = new Employee { Id = "new", Code = "EMP001", CompanyId = "c1" };

// Act

var result = await employee.ValidateAsync(repoMock.Object, CancellationToken.None);

// Assert

Assert.False(result.IsValid);

Assert.Contains(result.Errors, e => e.Contains("already exists"));

}

[Fact]

public void ComputedProperty_IsActive_CalculatesCorrectly()

{

// Arrange

var activeEmployee = new Employee { Status = EmployeeStatus.Active, IsDeleted = false };

var inactiveEmployee = new Employee { Status = EmployeeStatus.Inactive, IsDeleted = false };

var deletedEmployee = new Employee { Status = EmployeeStatus.Active, IsDeleted = true };

// Assert

Assert.True(activeEmployee.IsActive);

Assert.False(inactiveEmployee.IsActive);

Assert.False(deletedEmployee.IsActive);

}

}

```

Pattern 4: Angular Component Test

```typescript

describe('FeatureListComponent', () => {

let component: FeatureListComponent;

let fixture: ComponentFixture;

let store: FeatureListStore;

let apiMock: jasmine.SpyObj;

beforeEach(async () => {

apiMock = jasmine.createSpyObj('FeatureApiService', ['getList', 'delete']);

await TestBed.configureTestingModule({

imports: [FeatureListComponent],

providers: [FeatureListStore, { provide: FeatureApiService, useValue: apiMock }]

}).compileComponents();

fixture = TestBed.createComponent(FeatureListComponent);

component = fixture.componentInstance;

store = TestBed.inject(FeatureListStore);

});

it('should create', () => {

expect(component).toBeTruthy();

});

it('should load items on init', () => {

// Arrange

const items = [{ id: '1', name: 'Test' }];

apiMock.getList.and.returnValue(of({ items, totalCount: 1 }));

// Act

fixture.detectChanges();

// Assert

expect(apiMock.getList).toHaveBeenCalled();

expect(component.vm()?.items).toEqual(items);

});

it('should delete item', fakeAsync(() => {

// Arrange

store.updateState({ items: [{ id: '1', name: 'Test' }] });

apiMock.delete.and.returnValue(of(void 0));

// Act

component.onDelete({ id: '1', name: 'Test' });

tick();

// Assert

expect(apiMock.delete).toHaveBeenCalledWith('1');

expect(component.vm()?.items.length).toBe(0);

}));

it('should show loading state', () => {

// Arrange

apiMock.getList.and.returnValue(new Subject()); // Never completes

// Act

fixture.detectChanges();

// Assert

expect(store.isLoading$('loadItems')()).toBe(true);

});

});

```

Pattern 5: Angular Store Test

```typescript

describe('FeatureListStore', () => {

let store: FeatureListStore;

let apiMock: jasmine.SpyObj;

beforeEach(() => {

apiMock = jasmine.createSpyObj('FeatureApiService', ['getList', 'save', 'delete']);

TestBed.configureTestingModule({

providers: [FeatureListStore, { provide: FeatureApiService, useValue: apiMock }]

});

store = TestBed.inject(FeatureListStore);

});

it('should initialize with default state', () => {

expect(store.currentVm().items).toEqual([]);

expect(store.currentVm().pagination.pageIndex).toBe(0);

});

it('should load items', fakeAsync(() => {

// Arrange

const items = [{ id: '1', name: 'Test' }];

apiMock.getList.and.returnValue(of({ items, totalCount: 1 }));

// Act

store.loadItems();

tick();

// Assert

expect(store.currentVm().items).toEqual(items);

expect(store.currentVm().pagination.totalCount).toBe(1);

}));

it('should update state immutably', () => {

// Arrange

const initialItems = store.currentVm().items;

// Act

store.updateState({ items: [{ id: '1', name: 'New' }] });

// Assert

expect(store.currentVm().items).not.toBe(initialItems);

});

it('should handle API error', fakeAsync(() => {

// Arrange

apiMock.getList.and.returnValue(throwError(() => new Error('API Error')));

// Act

store.loadItems();

tick();

// Assert

expect(store.getErrorMsg$('loadItems')()).toContain('Error');

}));

});

```

Test Naming Convention

```

[MethodName]_[Scenario]_[ExpectedBehavior]

Examples:

  • HandleAsync_ValidCommand_ReturnsSuccess
  • HandleAsync_InvalidId_ThrowsNotFound
  • UniqueExpr_MatchingValues_ReturnsTrue
  • LoadItems_ApiError_SetsErrorState

```

Anti-Patterns to AVOID

:x: Testing implementation, not behavior

```csharp

// WRONG - testing internal method calls

Assert.True(handler.WasValidateCalled);

// CORRECT - testing observable behavior

Assert.Equal("Expected", result.Value);

```

:x: Not mocking dependencies

```csharp

// WRONG - using real repository

var handler = new Handler(new RealRepository());

// CORRECT - using mock

var repoMock = new Mock();

var handler = new Handler(repoMock.Object);

```

:x: Missing edge cases

```csharp

// WRONG - only happy path

[Fact] public void Save_ValidData_Succeeds() { }

// CORRECT - include edge cases

[Fact] public void Save_EmptyName_ReturnsError() { }

[Fact] public void Save_DuplicateCode_ReturnsError() { }

[Fact] public void Save_NullInput_ThrowsException() { }

```

Verification Checklist

  • [ ] Unit tests cover happy path
  • [ ] Edge cases and error conditions tested
  • [ ] Dependencies properly mocked
  • [ ] Test naming follows convention
  • [ ] Assertions are specific and meaningful
  • [ ] No test interdependencies
  • [ ] Tests are deterministic (no random, no time-dependent)

IMPORTANT Task Planning Notes

  • Always plan and break many small todo tasks
  • Always add a final review todo task to review the works done at the end to find any fix or enhancement needed