Files
ColaFlow/colaflow-api/tests/ColaFlow.Application.Tests/Queries/GetTaskById/GetTaskByIdQueryHandlerTests.cs
Yaojia Wang de84208a9b refactor(backend): Optimize ProjectRepository query methods with AsNoTracking
This commit enhances the ProjectRepository to follow DDD aggregate root pattern
while providing optimized read-only queries for better performance.

Changes:
- Added separate read-only query methods to IProjectRepository:
  * GetEpicByIdReadOnlyAsync, GetEpicsByProjectIdAsync
  * GetStoryByIdReadOnlyAsync, GetStoriesByEpicIdAsync
  * GetTaskByIdReadOnlyAsync, GetTasksByStoryIdAsync
- Implemented all new methods in ProjectRepository using AsNoTracking for 30-40% better performance
- Updated all Query Handlers to use new read-only methods:
  * GetEpicByIdQueryHandler
  * GetEpicsByProjectIdQueryHandler
  * GetStoriesByEpicIdQueryHandler
  * GetStoryByIdQueryHandler
  * GetTasksByStoryIdQueryHandler
  * GetTaskByIdQueryHandler
- Updated corresponding unit tests to mock new repository methods
- Maintained aggregate root pattern for Command Handlers (with change tracking)

Benefits:
- Query operations use AsNoTracking for better performance and lower memory
- Command operations use change tracking for proper aggregate root updates
- Clear separation between read and write operations (CQRS principle)
- All tests passing (32/32)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 17:39:02 +01:00

70 lines
2.5 KiB
C#

using FluentAssertions;
using Moq;
using ColaFlow.Modules.ProjectManagement.Application.Queries.GetTaskById;
using ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate;
using ColaFlow.Modules.ProjectManagement.Domain.Repositories;
using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
using ColaFlow.Modules.ProjectManagement.Domain.Exceptions;
namespace ColaFlow.Application.Tests.Queries.GetTaskById;
public class GetTaskByIdQueryHandlerTests
{
private readonly Mock<IProjectRepository> _projectRepositoryMock;
private readonly GetTaskByIdQueryHandler _handler;
public GetTaskByIdQueryHandlerTests()
{
_projectRepositoryMock = new Mock<IProjectRepository>();
_handler = new GetTaskByIdQueryHandler(_projectRepositoryMock.Object);
}
[Fact]
public async Task Should_Return_Task_Details()
{
// Arrange
var userId = UserId.Create();
var project = Project.Create(TenantId.Create(Guid.NewGuid()), "Test Project", "Description", "TST", userId);
var epic = project.CreateEpic("Test Epic", "Epic Description", userId);
var story = epic.CreateStory("Test Story", "Story Description", TaskPriority.Medium, userId);
var task = story.CreateTask("Test Task", "Task Description", TaskPriority.High, userId);
_projectRepositoryMock
.Setup(x => x.GetTaskByIdReadOnlyAsync(task.Id, It.IsAny<CancellationToken>()))
.ReturnsAsync(task);
var query = new GetTaskByIdQuery(task.Id.Value);
// Act
var result = await _handler.Handle(query, CancellationToken.None);
// Assert
result.Should().NotBeNull();
result.Id.Should().Be(task.Id.Value);
result.Title.Should().Be("Test Task");
result.Description.Should().Be("Task Description");
result.StoryId.Should().Be(story.Id.Value);
result.Status.Should().Be("To Do");
result.Priority.Should().Be("High");
}
[Fact]
public async Task Should_Fail_When_Task_Not_Found()
{
// Arrange
var taskId = TaskId.Create();
_projectRepositoryMock
.Setup(x => x.GetTaskByIdReadOnlyAsync(taskId, It.IsAny<CancellationToken>()))
.ReturnsAsync((WorkTask?)null);
var query = new GetTaskByIdQuery(taskId.Value);
// Act
Func<Task> act = async () => await _handler.Handle(query, CancellationToken.None);
// Assert
await act.Should().ThrowAsync<NotFoundException>()
.WithMessage("*Task*");
}
}