Files
pos-system/services/membership-service-net/tests/MembershipService.UnitTests/Domain/MemberAggregateTests.cs

201 lines
5.8 KiB
C#

using FluentAssertions;
using MembershipService.Domain.AggregatesModel.ExperienceAggregate;
using MembershipService.Domain.AggregatesModel.LevelAggregate;
using MembershipService.Domain.AggregatesModel.MemberAggregate;
using MembershipService.Domain.Events;
using Xunit;
namespace MembershipService.UnitTests.Domain;
/// <summary>
/// EN: Unit tests for Member aggregate.
/// VI: Unit tests cho Member aggregate.
/// </summary>
public class MemberAggregateTests
{
[Fact]
public void CreateMember_WithValidUserId_ShouldCreateMemberWithLevel1()
{
// Arrange
var userId = Guid.NewGuid();
// Act
var member = new Member(userId);
// Assert
member.Id.Should().Be(userId);
member.UserId.Should().Be(userId);
member.CurrentLevel.Should().Be(1);
member.CurrentExp.Should().Be(0);
member.TotalExpEarned.Should().Be(0);
member.CountryCode.Should().Be("VN");
member.IsDeleted.Should().BeFalse();
member.DomainEvents.Should().ContainSingle();
}
[Fact]
public void CreateMember_WithCustomCountryCode_ShouldSetCountryCode()
{
// Arrange
var userId = Guid.NewGuid();
// Act
var member = new Member(userId, "US");
// Assert
member.CountryCode.Should().Be("US");
}
[Fact]
public void CreateMember_WithGender_ShouldSetGender()
{
// Arrange
var userId = Guid.NewGuid();
// Act
var member = new Member(userId, "VN", "Male");
// Assert
member.Gender.Should().Be("Male");
member.CountryCode.Should().Be("VN");
}
[Fact]
public void UpdateGender_ShouldUpdateFieldAndRaiseEvent()
{
// Arrange
var member = new Member(Guid.NewGuid());
member.ClearDomainEvents();
// Act
member.UpdateGender("Female");
// Assert
member.Gender.Should().Be("Female");
member.DomainEvents.Should().ContainSingle();
}
[Fact]
public void UpdateCountryCode_ShouldUpdateFieldAndRaiseEvent()
{
// Arrange
var member = new Member(Guid.NewGuid());
member.ClearDomainEvents();
// Act
member.UpdateCountryCode("US");
// Assert
member.CountryCode.Should().Be("US");
member.DomainEvents.Should().ContainSingle();
}
[Fact]
public void UpdatePreferences_ShouldUpdateFieldAndRaiseEvent()
{
// Arrange
var member = new Member(Guid.NewGuid());
member.ClearDomainEvents();
var preferences = "{\"theme\": \"dark\", \"language\": \"vi\"}";
// Act
member.UpdatePreferences(preferences);
// Assert
member.Preferences.Should().Be(preferences);
member.DomainEvents.Should().ContainSingle();
}
[Fact]
public void AddExperience_ShouldAddExpAndRaiseEvent()
{
// Arrange
var member = new Member(Guid.NewGuid());
member.ClearDomainEvents();
var levelRules = CreateDefaultLevelRules();
// Act
var transaction = member.AddExperience(50, ExperienceSource.Purchase, levelRules, "ORDER-123");
// Assert
member.CurrentExp.Should().Be(50);
member.TotalExpEarned.Should().Be(50);
member.CurrentLevel.Should().Be(1); // Not enough for level 2
transaction.Points.Should().Be(50);
transaction.Source.Should().Be(ExperienceSource.Purchase);
transaction.ReferenceId.Should().Be("ORDER-123");
member.DomainEvents.Should().ContainSingle(e => e is MemberExperienceAddedDomainEvent);
}
[Fact]
public void AddExperience_ShouldLevelUp_WhenThresholdReached()
{
// Arrange
var member = new Member(Guid.NewGuid());
member.ClearDomainEvents();
var levelRules = CreateDefaultLevelRules();
// Act
var transaction = member.AddExperience(150, ExperienceSource.Purchase, levelRules);
// Assert
member.CurrentExp.Should().Be(150);
member.CurrentLevel.Should().Be(2); // Silver at 100 EXP
member.DomainEvents.Should().Contain(e => e is MemberLevelUpDomainEvent);
member.DomainEvents.Should().Contain(e => e is MemberExperienceAddedDomainEvent);
}
[Fact]
public void AddExperience_ShouldLevelUpMultipleLevels_WhenBigExpGain()
{
// Arrange
var member = new Member(Guid.NewGuid());
member.ClearDomainEvents();
var levelRules = CreateDefaultLevelRules();
// Act
member.AddExperience(500, ExperienceSource.Admin, levelRules);
// Assert
member.CurrentExp.Should().Be(500);
member.CurrentLevel.Should().Be(3); // Gold at 300 EXP
}
[Fact]
public void AddExperience_WithNegativePoints_ShouldThrow()
{
// Arrange
var member = new Member(Guid.NewGuid());
var levelRules = CreateDefaultLevelRules();
// Act & Assert
var act = () => member.AddExperience(-10, ExperienceSource.Purchase, levelRules);
act.Should().Throw<ArgumentException>().WithMessage("*positive*");
}
[Fact]
public void Delete_ShouldMarkAsDeleted()
{
// Arrange
var member = new Member(Guid.NewGuid());
// Act
member.Delete();
// Assert
member.IsDeleted.Should().BeTrue();
}
private static IReadOnlyList<LevelDefinition> CreateDefaultLevelRules()
{
return new List<LevelDefinition>
{
new LevelDefinition(1, "Bronze", 0, "Starting level"),
new LevelDefinition(2, "Silver", 100, "Reach 100 EXP"),
new LevelDefinition(3, "Gold", 300, "Reach 300 EXP"),
new LevelDefinition(4, "Platinum", 600, "Reach 600 EXP"),
new LevelDefinition(5, "Diamond", 1000, "Reach 1000 EXP")
};
}
}