Files
ChatBot/ChatBot.Tests/TestUtilities/TestDataBuilder.cs
Leonid Pershin 1996fec14f
All checks were successful
SonarQube / Build and analyze (push) Successful in 2m54s
Add promt fix tests
2025-10-21 12:07:56 +03:00

335 lines
10 KiB
C#

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.GetOrCreateAsync(It.IsAny<long>(), It.IsAny<string>(), It.IsAny<string>()))
.ReturnsAsync((long chatId, string chatType, string chatTitle) =>
{
if (!sessions.TryGetValue(chatId, out var session))
{
session = TestDataBuilder.ChatSessions.CreateBasicSession(
chatId,
chatType
);
session.ChatTitle = chatTitle;
sessions[chatId] = session;
}
return session;
});
mock.Setup(x => x.GetAsync(It.IsAny<long>()))
.ReturnsAsync((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.RemoveAsync(It.IsAny<long>()))
.ReturnsAsync((long chatId) => sessions.Remove(chatId));
mock.Setup(x => x.GetActiveSessionsCountAsync()).ReturnsAsync(() => sessions.Count);
mock.Setup(x => x.CleanupOldSessionsAsync(It.IsAny<int>())).ReturnsAsync((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;
}
}
}