201 lines
5.8 KiB
C#
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")
|
|
};
|
|
}
|
|
}
|