add tests
This commit is contained in:
336
ChatBot.Tests/TestUtilities/TestDataBuilder.cs
Normal file
336
ChatBot.Tests/TestUtilities/TestDataBuilder.cs
Normal file
@@ -0,0 +1,336 @@
|
||||
using ChatBot.Models;
|
||||
using ChatBot.Models.Configuration;
|
||||
using ChatBot.Models.Dto;
|
||||
using ChatBot.Models.Entities;
|
||||
using ChatBot.Services.Interfaces;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using OllamaSharp.Models.Chat;
|
||||
using Telegram.Bot;
|
||||
|
||||
namespace ChatBot.Tests.TestUtilities;
|
||||
|
||||
/// <summary>
|
||||
/// Builder pattern for creating test data and mocks
|
||||
/// </summary>
|
||||
public static class TestDataBuilder
|
||||
{
|
||||
public static class ChatSessions
|
||||
{
|
||||
public static ChatSession CreateBasicSession(
|
||||
long chatId = 12345,
|
||||
string chatType = "private"
|
||||
)
|
||||
{
|
||||
return new ChatSession
|
||||
{
|
||||
ChatId = chatId,
|
||||
ChatType = chatType,
|
||||
ChatTitle = chatType == "private" ? "" : "Test Group",
|
||||
Model = "llama3.2",
|
||||
CreatedAt = DateTime.UtcNow.AddHours(-1),
|
||||
LastUpdatedAt = DateTime.UtcNow,
|
||||
};
|
||||
}
|
||||
|
||||
public static ChatSession CreateSessionWithMessages(
|
||||
long chatId = 12345,
|
||||
int messageCount = 3
|
||||
)
|
||||
{
|
||||
var session = CreateBasicSession(chatId);
|
||||
|
||||
for (int i = 0; i < messageCount; i++)
|
||||
{
|
||||
session.AddUserMessage($"Test message {i + 1}", "testuser");
|
||||
session.AddAssistantMessage($"AI response {i + 1}");
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ChatMessages
|
||||
{
|
||||
public static ChatMessage CreateUserMessage(
|
||||
string content = "Hello",
|
||||
string username = "testuser"
|
||||
)
|
||||
{
|
||||
return new ChatMessage { Role = ChatRole.User, Content = content };
|
||||
}
|
||||
|
||||
public static ChatMessage CreateAssistantMessage(
|
||||
string content = "Hello! How can I help you?"
|
||||
)
|
||||
{
|
||||
return new ChatMessage { Role = ChatRole.Assistant, Content = content };
|
||||
}
|
||||
|
||||
public static ChatMessage CreateSystemMessage(
|
||||
string content = "You are a helpful assistant."
|
||||
)
|
||||
{
|
||||
return new ChatMessage { Role = ChatRole.System, Content = content };
|
||||
}
|
||||
|
||||
public static List<ChatMessage> CreateMessageHistory(int count = 5)
|
||||
{
|
||||
var messages = new List<ChatMessage>();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
messages.Add(CreateUserMessage($"User message {i + 1}"));
|
||||
messages.Add(CreateAssistantMessage($"Assistant response {i + 1}"));
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Configurations
|
||||
{
|
||||
public static AISettings CreateAISettings()
|
||||
{
|
||||
return new AISettings
|
||||
{
|
||||
Temperature = 0.7,
|
||||
MaxRetryAttempts = 3,
|
||||
RetryDelayMs = 1000,
|
||||
MaxRetryDelayMs = 10000,
|
||||
EnableExponentialBackoff = true,
|
||||
RequestTimeoutSeconds = 30,
|
||||
EnableHistoryCompression = true,
|
||||
CompressionThreshold = 10,
|
||||
CompressionTarget = 5,
|
||||
MinMessageLengthForSummarization = 50,
|
||||
MaxSummarizedMessageLength = 200,
|
||||
CompressionTimeoutSeconds = 15,
|
||||
};
|
||||
}
|
||||
|
||||
public static OllamaSettings CreateOllamaSettings()
|
||||
{
|
||||
return new OllamaSettings { Url = "http://localhost:11434", DefaultModel = "llama3.2" };
|
||||
}
|
||||
|
||||
public static TelegramBotSettings CreateTelegramBotSettings()
|
||||
{
|
||||
return new TelegramBotSettings { BotToken = "test-bot-token" };
|
||||
}
|
||||
|
||||
public static DatabaseSettings CreateDatabaseSettings()
|
||||
{
|
||||
return new DatabaseSettings
|
||||
{
|
||||
ConnectionString =
|
||||
"Host=localhost;Port=5432;Database=test_chatbot;Username=test;Password=test",
|
||||
CommandTimeout = 30,
|
||||
EnableSensitiveDataLogging = false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class Mocks
|
||||
{
|
||||
public static Mock<ILogger<T>> CreateLoggerMock<T>()
|
||||
{
|
||||
return new Mock<ILogger<T>>();
|
||||
}
|
||||
|
||||
public static Mock<IOptions<T>> CreateOptionsMock<T>(T value)
|
||||
where T : class
|
||||
{
|
||||
var mock = new Mock<IOptions<T>>();
|
||||
mock.Setup(x => x.Value).Returns(value);
|
||||
return mock;
|
||||
}
|
||||
|
||||
public static Mock<ISessionStorage> CreateSessionStorageMock()
|
||||
{
|
||||
var mock = new Mock<ISessionStorage>();
|
||||
var sessions = new Dictionary<long, ChatSession>();
|
||||
|
||||
mock.Setup(x => x.GetOrCreate(It.IsAny<long>(), It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Returns<long, string, string>(
|
||||
(chatId, chatType, chatTitle) =>
|
||||
{
|
||||
if (!sessions.ContainsKey(chatId))
|
||||
{
|
||||
var session = TestDataBuilder.ChatSessions.CreateBasicSession(
|
||||
chatId,
|
||||
chatType
|
||||
);
|
||||
session.ChatTitle = chatTitle;
|
||||
sessions[chatId] = session;
|
||||
}
|
||||
return sessions[chatId];
|
||||
}
|
||||
);
|
||||
|
||||
mock.Setup(x => x.Get(It.IsAny<long>()))
|
||||
.Returns<long>(chatId =>
|
||||
sessions.TryGetValue(chatId, out var session) ? session : null
|
||||
);
|
||||
|
||||
mock.Setup(x => x.SaveSessionAsync(It.IsAny<ChatSession>()))
|
||||
.Returns<ChatSession>(session =>
|
||||
{
|
||||
sessions[session.ChatId] = session;
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
mock.Setup(x => x.Remove(It.IsAny<long>()))
|
||||
.Returns<long>(chatId => sessions.Remove(chatId));
|
||||
|
||||
mock.Setup(x => x.GetActiveSessionsCount()).Returns(() => sessions.Count);
|
||||
|
||||
mock.Setup(x => x.CleanupOldSessions(It.IsAny<int>())).Returns<int>(hoursOld => 0);
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
public static Mock<IAIService> CreateAIServiceMock()
|
||||
{
|
||||
var mock = new Mock<IAIService>();
|
||||
|
||||
mock.Setup(x =>
|
||||
x.GenerateChatCompletionAsync(
|
||||
It.IsAny<List<ChatMessage>>(),
|
||||
It.IsAny<CancellationToken>()
|
||||
)
|
||||
)
|
||||
.ReturnsAsync("Test AI response");
|
||||
|
||||
mock.Setup(x =>
|
||||
x.GenerateChatCompletionWithCompressionAsync(
|
||||
It.IsAny<List<ChatMessage>>(),
|
||||
It.IsAny<CancellationToken>()
|
||||
)
|
||||
)
|
||||
.ReturnsAsync("Test AI response with compression");
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
public static Mock<IHistoryCompressionService> CreateCompressionServiceMock()
|
||||
{
|
||||
var mock = new Mock<IHistoryCompressionService>();
|
||||
|
||||
mock.Setup(x => x.ShouldCompress(It.IsAny<int>(), It.IsAny<int>()))
|
||||
.Returns<int, int>((count, threshold) => count > threshold);
|
||||
|
||||
mock.Setup(x =>
|
||||
x.CompressHistoryAsync(
|
||||
It.IsAny<List<ChatMessage>>(),
|
||||
It.IsAny<int>(),
|
||||
It.IsAny<CancellationToken>()
|
||||
)
|
||||
)
|
||||
.ReturnsAsync(
|
||||
(List<ChatMessage> messages, int targetCount, CancellationToken ct) =>
|
||||
{
|
||||
// Simple compression: take last targetCount messages
|
||||
return messages.TakeLast(targetCount).ToList();
|
||||
}
|
||||
);
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
public static Mock<IOllamaClient> CreateOllamaClientMock()
|
||||
{
|
||||
var mock = new Mock<IOllamaClient>();
|
||||
|
||||
mock.Setup(x => x.ChatAsync(It.IsAny<OllamaSharp.Models.Chat.ChatRequest>()))
|
||||
.Returns(
|
||||
TestDataBuilder.Mocks.CreateAsyncEnumerable(
|
||||
new List<OllamaSharp.Models.Chat.ChatResponseStream>()
|
||||
)
|
||||
);
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a mock chat session entity
|
||||
/// </summary>
|
||||
public static ChatSessionEntity CreateChatSessionEntity(
|
||||
int id = 1,
|
||||
long chatId = 12345,
|
||||
string sessionId = "test-session",
|
||||
string chatType = "private",
|
||||
string chatTitle = "Test Chat"
|
||||
)
|
||||
{
|
||||
return new ChatSessionEntity
|
||||
{
|
||||
Id = id,
|
||||
ChatId = chatId,
|
||||
SessionId = sessionId,
|
||||
ChatType = chatType,
|
||||
ChatTitle = chatTitle,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
LastUpdatedAt = DateTime.UtcNow,
|
||||
Messages = new List<ChatMessageEntity>(),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a mock chat message entity
|
||||
/// </summary>
|
||||
public static ChatMessageEntity CreateChatMessageEntity(
|
||||
int id = 1,
|
||||
int sessionId = 1,
|
||||
string content = "Test message",
|
||||
string role = "user",
|
||||
int messageOrder = 1
|
||||
)
|
||||
{
|
||||
return new ChatMessageEntity
|
||||
{
|
||||
Id = id,
|
||||
SessionId = sessionId,
|
||||
Content = content,
|
||||
Role = role,
|
||||
MessageOrder = messageOrder,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a mock Telegram bot client
|
||||
/// </summary>
|
||||
public static Mock<ITelegramBotClient> CreateTelegramBotClient()
|
||||
{
|
||||
var mock = new Mock<ITelegramBotClient>();
|
||||
return mock;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a mock Telegram bot user
|
||||
/// </summary>
|
||||
public static global::Telegram.Bot.Types.User CreateTelegramBot()
|
||||
{
|
||||
return new global::Telegram.Bot.Types.User
|
||||
{
|
||||
Id = 12345,
|
||||
Username = "test_bot",
|
||||
FirstName = "Test Bot",
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create async enumerable from list
|
||||
/// </summary>
|
||||
public static async IAsyncEnumerable<T> CreateAsyncEnumerable<T>(IEnumerable<T> items)
|
||||
{
|
||||
foreach (var item in items)
|
||||
{
|
||||
yield return item;
|
||||
}
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user