199 lines
5.1 KiB
C#
199 lines
5.1 KiB
C#
namespace MissionService.UnitTests.Domain;
|
|
|
|
using FluentAssertions;
|
|
using MissionService.Domain.AggregatesModel.CheckInAggregate;
|
|
using Xunit;
|
|
|
|
/// <summary>
|
|
/// EN: Tests for UserCheckIn aggregate root invariants and behavior.
|
|
/// VI: Kiểm thử các quy tắc bất biến và hành vi của UserCheckIn aggregate root.
|
|
/// </summary>
|
|
public class UserCheckInAggregateTests
|
|
{
|
|
private readonly StreakBonusConfig _defaultConfig = StreakBonusConfig.Default();
|
|
|
|
#region Constructor Tests
|
|
|
|
[Fact]
|
|
public void Constructor_ValidUserId_CreatesCheckInWithZeroStreak()
|
|
{
|
|
// Arrange
|
|
var userId = Guid.NewGuid();
|
|
|
|
// Act
|
|
var checkIn = new UserCheckIn(userId);
|
|
|
|
// Assert
|
|
checkIn.UserId.Should().Be(userId);
|
|
checkIn.CurrentStreak.Should().Be(0);
|
|
checkIn.LongestStreak.Should().Be(0);
|
|
checkIn.TotalCheckIns.Should().Be(0);
|
|
checkIn.LastCheckInDate.Should().BeNull();
|
|
checkIn.CheckInDays.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Constructor_EmptyUserId_ThrowsArgumentException()
|
|
{
|
|
// Arrange & Act
|
|
var act = () => new UserCheckIn(Guid.Empty);
|
|
|
|
// Assert
|
|
act.Should().Throw<ArgumentException>()
|
|
.WithMessage("*User ID is required*");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CanCheckInToday Tests
|
|
|
|
[Fact]
|
|
public void CanCheckInToday_NewUser_ReturnsTrue()
|
|
{
|
|
// Arrange
|
|
var checkIn = new UserCheckIn(Guid.NewGuid());
|
|
|
|
// Act
|
|
var result = checkIn.CanCheckInToday();
|
|
|
|
// Assert
|
|
result.Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void CanCheckInToday_AfterCheckIn_ReturnsFalse()
|
|
{
|
|
// Arrange
|
|
var checkIn = new UserCheckIn(Guid.NewGuid());
|
|
checkIn.CheckIn(_defaultConfig);
|
|
|
|
// Act
|
|
var result = checkIn.CanCheckInToday();
|
|
|
|
// Assert
|
|
result.Should().BeFalse();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CheckIn Tests
|
|
|
|
[Fact]
|
|
public void CheckIn_FirstTime_SetsStreakToOne()
|
|
{
|
|
// Arrange
|
|
var checkIn = new UserCheckIn(Guid.NewGuid());
|
|
|
|
// Act
|
|
var result = checkIn.CheckIn(_defaultConfig);
|
|
|
|
// Assert
|
|
checkIn.CurrentStreak.Should().Be(1);
|
|
checkIn.LongestStreak.Should().Be(1);
|
|
checkIn.TotalCheckIns.Should().Be(1);
|
|
result.CurrentStreak.Should().Be(1);
|
|
}
|
|
|
|
[Fact]
|
|
public void CheckIn_FirstTime_AwardsDailyPoints()
|
|
{
|
|
// Arrange
|
|
var checkIn = new UserCheckIn(Guid.NewGuid());
|
|
|
|
// Act
|
|
var result = checkIn.CheckIn(_defaultConfig);
|
|
|
|
// Assert
|
|
result.DailyPoints.Should().BeGreaterThan(0);
|
|
result.TotalPoints.Should().BeGreaterThanOrEqualTo(result.DailyPoints);
|
|
}
|
|
|
|
[Fact]
|
|
public void CheckIn_AlreadyCheckedInToday_ThrowsInvalidOperationException()
|
|
{
|
|
// Arrange
|
|
var checkIn = new UserCheckIn(Guid.NewGuid());
|
|
checkIn.CheckIn(_defaultConfig);
|
|
|
|
// Act
|
|
var act = () => checkIn.CheckIn(_defaultConfig);
|
|
|
|
// Assert
|
|
act.Should().Throw<InvalidOperationException>()
|
|
.WithMessage("*Already checked in today*");
|
|
}
|
|
|
|
[Fact]
|
|
public void CheckIn_AddsCheckInDayRecord()
|
|
{
|
|
// Arrange
|
|
var checkIn = new UserCheckIn(Guid.NewGuid());
|
|
|
|
// Act
|
|
var result = checkIn.CheckIn(_defaultConfig);
|
|
|
|
// Assert
|
|
checkIn.CheckInDays.Should().HaveCount(1);
|
|
var dayRecord = checkIn.CheckInDays.First();
|
|
dayRecord.PointsEarned.Should().Be(result.TotalPoints);
|
|
dayRecord.StreakOnDay.Should().Be(1);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ResetStreak Tests
|
|
|
|
[Fact]
|
|
public void ResetStreak_WithActiveStreak_ResetsCurrentStreakToZero()
|
|
{
|
|
// Arrange
|
|
var checkIn = new UserCheckIn(Guid.NewGuid());
|
|
checkIn.CheckIn(_defaultConfig);
|
|
checkIn.CurrentStreak.Should().Be(1);
|
|
|
|
// Act
|
|
checkIn.ResetStreak();
|
|
|
|
// Assert
|
|
checkIn.CurrentStreak.Should().Be(0);
|
|
// EN: LongestStreak should remain unchanged
|
|
// VI: LongestStreak nên giữ nguyên
|
|
checkIn.LongestStreak.Should().Be(1);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetMonthlyCheckIns Tests
|
|
|
|
[Fact]
|
|
public void GetMonthlyCheckIns_NoCheckIns_ReturnsEmptyList()
|
|
{
|
|
// Arrange
|
|
var checkIn = new UserCheckIn(Guid.NewGuid());
|
|
var now = DateTime.UtcNow;
|
|
|
|
// Act
|
|
var result = checkIn.GetMonthlyCheckIns(now.Year, now.Month);
|
|
|
|
// Assert
|
|
result.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void GetMonthlyCheckIns_WithCheckIns_ReturnsCurrentMonthCheckIns()
|
|
{
|
|
// Arrange
|
|
var checkIn = new UserCheckIn(Guid.NewGuid());
|
|
checkIn.CheckIn(_defaultConfig);
|
|
var now = DateTime.UtcNow;
|
|
|
|
// Act
|
|
var result = checkIn.GetMonthlyCheckIns(now.Year, now.Month);
|
|
|
|
// Assert
|
|
result.Should().HaveCount(1);
|
|
}
|
|
|
|
#endregion
|
|
}
|