Project Init
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
332
colaflow-api/tests/ColaFlow.Domain.Tests/Aggregates/EpicTests.cs
Normal file
332
colaflow-api/tests/ColaFlow.Domain.Tests/Aggregates/EpicTests.cs
Normal file
@@ -0,0 +1,332 @@
|
||||
using ColaFlow.Modules.ProjectManagement.Domain.Aggregates.ProjectAggregate;
|
||||
using ColaFlow.Modules.ProjectManagement.Domain.ValueObjects;
|
||||
using ColaFlow.Modules.ProjectManagement.Domain.Exceptions;
|
||||
using FluentAssertions;
|
||||
|
||||
namespace ColaFlow.Domain.Tests.Aggregates;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for Epic entity
|
||||
/// </summary>
|
||||
public class EpicTests
|
||||
{
|
||||
#region Create Tests
|
||||
|
||||
[Fact]
|
||||
public void Create_WithValidData_ShouldCreateEpic()
|
||||
{
|
||||
// Arrange
|
||||
var name = "Epic 1";
|
||||
var description = "Epic Description";
|
||||
var projectId = ProjectId.Create();
|
||||
var createdBy = UserId.Create();
|
||||
|
||||
// Act
|
||||
var epic = Epic.Create(name, description, projectId, createdBy);
|
||||
|
||||
// Assert
|
||||
epic.Should().NotBeNull();
|
||||
epic.Name.Should().Be(name);
|
||||
epic.Description.Should().Be(description);
|
||||
epic.ProjectId.Should().Be(projectId);
|
||||
epic.Status.Should().Be(WorkItemStatus.ToDo);
|
||||
epic.Priority.Should().Be(TaskPriority.Medium);
|
||||
epic.CreatedBy.Should().Be(createdBy);
|
||||
epic.CreatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5));
|
||||
epic.UpdatedAt.Should().BeNull();
|
||||
epic.Stories.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_WithNullDescription_ShouldCreateEpicWithEmptyDescription()
|
||||
{
|
||||
// Arrange
|
||||
var name = "Epic 1";
|
||||
string? description = null;
|
||||
var projectId = ProjectId.Create();
|
||||
var createdBy = UserId.Create();
|
||||
|
||||
// Act
|
||||
var epic = Epic.Create(name, description!, projectId, createdBy);
|
||||
|
||||
// Assert
|
||||
epic.Should().NotBeNull();
|
||||
epic.Description.Should().Be(string.Empty);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData(" ")]
|
||||
[InlineData(null)]
|
||||
public void Create_WithEmptyName_ShouldThrowDomainException(string invalidName)
|
||||
{
|
||||
// Arrange
|
||||
var projectId = ProjectId.Create();
|
||||
var createdBy = UserId.Create();
|
||||
|
||||
// Act
|
||||
Action act = () => Epic.Create(invalidName, "Description", projectId, createdBy);
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<DomainException>()
|
||||
.WithMessage("Epic name cannot be empty");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_WithNameExceeding200Characters_ShouldThrowDomainException()
|
||||
{
|
||||
// Arrange
|
||||
var name = new string('A', 201);
|
||||
var projectId = ProjectId.Create();
|
||||
var createdBy = UserId.Create();
|
||||
|
||||
// Act
|
||||
Action act = () => Epic.Create(name, "Description", projectId, createdBy);
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<DomainException>()
|
||||
.WithMessage("Epic name cannot exceed 200 characters");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Create_WithNameExactly200Characters_ShouldSucceed()
|
||||
{
|
||||
// Arrange
|
||||
var name = new string('A', 200);
|
||||
var projectId = ProjectId.Create();
|
||||
var createdBy = UserId.Create();
|
||||
|
||||
// Act
|
||||
var epic = Epic.Create(name, "Description", projectId, createdBy);
|
||||
|
||||
// Assert
|
||||
epic.Should().NotBeNull();
|
||||
epic.Name.Should().Be(name);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region CreateStory Tests
|
||||
|
||||
[Fact]
|
||||
public void CreateStory_WithValidData_ShouldCreateStory()
|
||||
{
|
||||
// Arrange
|
||||
var epic = Epic.Create("Epic 1", "Description", ProjectId.Create(), UserId.Create());
|
||||
var storyTitle = "Story 1";
|
||||
var storyDescription = "Story Description";
|
||||
var priority = TaskPriority.High;
|
||||
var createdBy = UserId.Create();
|
||||
|
||||
// Act
|
||||
var story = epic.CreateStory(storyTitle, storyDescription, priority, createdBy);
|
||||
|
||||
// Assert
|
||||
story.Should().NotBeNull();
|
||||
story.Title.Should().Be(storyTitle);
|
||||
story.Description.Should().Be(storyDescription);
|
||||
story.EpicId.Should().Be(epic.Id);
|
||||
story.Priority.Should().Be(priority);
|
||||
story.CreatedBy.Should().Be(createdBy);
|
||||
epic.Stories.Should().ContainSingle();
|
||||
epic.Stories.Should().Contain(story);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateStory_MultipleStories_ShouldAddToCollection()
|
||||
{
|
||||
// Arrange
|
||||
var epic = Epic.Create("Epic 1", "Description", ProjectId.Create(), UserId.Create());
|
||||
var createdBy = UserId.Create();
|
||||
|
||||
// Act
|
||||
var story1 = epic.CreateStory("Story 1", "Desc 1", TaskPriority.Low, createdBy);
|
||||
var story2 = epic.CreateStory("Story 2", "Desc 2", TaskPriority.Medium, createdBy);
|
||||
var story3 = epic.CreateStory("Story 3", "Desc 3", TaskPriority.High, createdBy);
|
||||
|
||||
// Assert
|
||||
epic.Stories.Should().HaveCount(3);
|
||||
epic.Stories.Should().Contain(new[] { story1, story2, story3 });
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UpdateDetails Tests
|
||||
|
||||
[Fact]
|
||||
public void UpdateDetails_WithValidData_ShouldUpdateEpic()
|
||||
{
|
||||
// Arrange
|
||||
var epic = Epic.Create("Original Name", "Original Description", ProjectId.Create(), UserId.Create());
|
||||
var originalCreatedAt = epic.CreatedAt;
|
||||
var newName = "Updated Name";
|
||||
var newDescription = "Updated Description";
|
||||
|
||||
// Act
|
||||
epic.UpdateDetails(newName, newDescription);
|
||||
|
||||
// Assert
|
||||
epic.Name.Should().Be(newName);
|
||||
epic.Description.Should().Be(newDescription);
|
||||
epic.CreatedAt.Should().Be(originalCreatedAt);
|
||||
epic.UpdatedAt.Should().NotBeNull();
|
||||
epic.UpdatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateDetails_WithNullDescription_ShouldSetEmptyDescription()
|
||||
{
|
||||
// Arrange
|
||||
var epic = Epic.Create("Original Name", "Original Description", ProjectId.Create(), UserId.Create());
|
||||
|
||||
// Act
|
||||
epic.UpdateDetails("Updated Name", null!);
|
||||
|
||||
// Assert
|
||||
epic.Description.Should().Be(string.Empty);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData(" ")]
|
||||
[InlineData(null)]
|
||||
public void UpdateDetails_WithEmptyName_ShouldThrowDomainException(string invalidName)
|
||||
{
|
||||
// Arrange
|
||||
var epic = Epic.Create("Original Name", "Original Description", ProjectId.Create(), UserId.Create());
|
||||
|
||||
// Act
|
||||
Action act = () => epic.UpdateDetails(invalidName, "Updated Description");
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<DomainException>()
|
||||
.WithMessage("Epic name cannot be empty");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateDetails_WithNameExceeding200Characters_ShouldThrowDomainException()
|
||||
{
|
||||
// Arrange
|
||||
var epic = Epic.Create("Original Name", "Original Description", ProjectId.Create(), UserId.Create());
|
||||
var name = new string('A', 201);
|
||||
|
||||
// Act
|
||||
Action act = () => epic.UpdateDetails(name, "Updated Description");
|
||||
|
||||
// Assert
|
||||
act.Should().Throw<DomainException>()
|
||||
.WithMessage("Epic name cannot exceed 200 characters");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UpdateStatus Tests
|
||||
|
||||
[Fact]
|
||||
public void UpdateStatus_WithValidStatus_ShouldUpdateStatus()
|
||||
{
|
||||
// Arrange
|
||||
var epic = Epic.Create("Epic 1", "Description", ProjectId.Create(), UserId.Create());
|
||||
var newStatus = WorkItemStatus.InProgress;
|
||||
|
||||
// Act
|
||||
epic.UpdateStatus(newStatus);
|
||||
|
||||
// Assert
|
||||
epic.Status.Should().Be(newStatus);
|
||||
epic.UpdatedAt.Should().NotBeNull();
|
||||
epic.UpdatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateStatus_ToAllStatuses_ShouldSucceed()
|
||||
{
|
||||
// Arrange
|
||||
var epic = Epic.Create("Epic 1", "Description", ProjectId.Create(), UserId.Create());
|
||||
|
||||
// Act & Assert
|
||||
epic.UpdateStatus(WorkItemStatus.InProgress);
|
||||
epic.Status.Should().Be(WorkItemStatus.InProgress);
|
||||
|
||||
epic.UpdateStatus(WorkItemStatus.InReview);
|
||||
epic.Status.Should().Be(WorkItemStatus.InReview);
|
||||
|
||||
epic.UpdateStatus(WorkItemStatus.Done);
|
||||
epic.Status.Should().Be(WorkItemStatus.Done);
|
||||
|
||||
epic.UpdateStatus(WorkItemStatus.Blocked);
|
||||
epic.Status.Should().Be(WorkItemStatus.Blocked);
|
||||
|
||||
epic.UpdateStatus(WorkItemStatus.ToDo);
|
||||
epic.Status.Should().Be(WorkItemStatus.ToDo);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region UpdatePriority Tests
|
||||
|
||||
[Fact]
|
||||
public void UpdatePriority_WithValidPriority_ShouldUpdatePriority()
|
||||
{
|
||||
// Arrange
|
||||
var epic = Epic.Create("Epic 1", "Description", ProjectId.Create(), UserId.Create());
|
||||
var newPriority = TaskPriority.Urgent;
|
||||
|
||||
// Act
|
||||
epic.UpdatePriority(newPriority);
|
||||
|
||||
// Assert
|
||||
epic.Priority.Should().Be(newPriority);
|
||||
epic.UpdatedAt.Should().NotBeNull();
|
||||
epic.UpdatedAt.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdatePriority_ToAllPriorities_ShouldSucceed()
|
||||
{
|
||||
// Arrange
|
||||
var epic = Epic.Create("Epic 1", "Description", ProjectId.Create(), UserId.Create());
|
||||
|
||||
// Act & Assert
|
||||
epic.UpdatePriority(TaskPriority.Low);
|
||||
epic.Priority.Should().Be(TaskPriority.Low);
|
||||
|
||||
epic.UpdatePriority(TaskPriority.Medium);
|
||||
epic.Priority.Should().Be(TaskPriority.Medium);
|
||||
|
||||
epic.UpdatePriority(TaskPriority.High);
|
||||
epic.Priority.Should().Be(TaskPriority.High);
|
||||
|
||||
epic.UpdatePriority(TaskPriority.Urgent);
|
||||
epic.Priority.Should().Be(TaskPriority.Urgent);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Entity Characteristics Tests
|
||||
|
||||
[Fact]
|
||||
public void Stories_Collection_ShouldBeReadOnly()
|
||||
{
|
||||
// Arrange
|
||||
var epic = Epic.Create("Epic 1", "Description", ProjectId.Create(), UserId.Create());
|
||||
|
||||
// Act & Assert
|
||||
epic.Stories.Should().BeAssignableTo<IReadOnlyCollection<Story>>();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Epic_ShouldHaveUniqueId()
|
||||
{
|
||||
// Arrange & Act
|
||||
var projectId = ProjectId.Create();
|
||||
var createdBy = UserId.Create();
|
||||
var epic1 = Epic.Create("Epic 1", "Description", projectId, createdBy);
|
||||
var epic2 = Epic.Create("Epic 2", "Description", projectId, createdBy);
|
||||
|
||||
// Assert
|
||||
epic1.Id.Should().NotBe(epic2.Id);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user