Skip to content

Commit

Permalink
4. Unit & Integraion Test Implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisIvanov committed Jun 11, 2024
1 parent 6b6fea2 commit 0388c03
Show file tree
Hide file tree
Showing 6 changed files with 263 additions and 48 deletions.
10 changes: 4 additions & 6 deletions src/server/CookingApp/Controllers/ChatController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ public async Task<IActionResult> SendQuery([FromBody] string message, [FromHeade

var result =
String.IsNullOrEmpty(chatId)
? await _chatService.CreateChat(message)
: await _chatService.UpdateChat(message, chatId);
? await _chatService.CreateChatAsync(message)
: await _chatService.UpdateChatAsync(message, chatId);

if (result == null)
{
Expand All @@ -60,20 +60,18 @@ public async Task<IActionResult> SendQuery([FromBody] string message, [FromHeade
}

_logger.LogInformation(SuccessMessages.ChatGPT.ResponseSuccess);

// To display the message you need to get into result.Choices[0].Message.Content.
// The chat id is also contained inside the result

return Ok(result);
}
catch (Exception e)
{
_logger.LogError(ExceptionMessages.ChatGPT.ConnectionError);
_logger.LogError($"{e.Message}");

return BadRequest();
}

return Ok();
return BadRequest();
}
}
}
19 changes: 9 additions & 10 deletions src/server/CookingApp/Services/ChatService/ChatService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,16 @@ public class ChatService : IChatService
{
private readonly IRepository<Chat> _chatRepository;
private readonly ILogger<ChatService> _logger;
private readonly IChatService _chatService;
private readonly IOpenAIService _openAIService;
private readonly IRepository<User> _userRepository;

public ChatService(
IOpenAIService openAIService,
IChatService chatService,
ILogger<ChatService> logger,
IRepository<Chat> chatRepository,
IRepository<User> userRepository)
{
_openAIService = openAIService;
_chatService = chatService;
_logger = logger;
_chatRepository = chatRepository;
_userRepository = userRepository;
Expand Down Expand Up @@ -75,7 +72,7 @@ public async Task<int> DeleteAsync(string id)
return 0;
}

public async Task<ChatCompletionCreateResponse> CreateChat(string request)
public async Task<ChatCompletionCreateResponse> CreateChatAsync(string request)
{
try
{
Expand Down Expand Up @@ -109,8 +106,10 @@ public async Task<ChatCompletionCreateResponse> CreateChat(string request)

if (completionResult.Successful)
{
//var response = completionResult.Choices[0].Message.Content;
//UpdateUserChat(userChat, request, response);
_logger.LogInformation(SuccessMessages.ChatGPT.ResponseSuccess);
// workout if info is needed inside the logger
_logger.LogInformation($"{JsonSerializer.Serialize(completionResult)}");

return completionResult;
}
}
Expand All @@ -123,11 +122,11 @@ public async Task<ChatCompletionCreateResponse> CreateChat(string request)
return null;
}

public async Task<ChatCompletionCreateResponse> UpdateChat(string request, string? chatId)
public async Task<ChatCompletionCreateResponse> UpdateChatAsync(string request, string? chatId)
{
try
{
var userChat = await _chatService.GetByIdAsync(chatId);
var userChat = await GetByIdAsync(chatId);

var completionResult = await _openAIService.ChatCompletion.CreateCompletion(new ChatCompletionCreateRequest
{
Expand Down Expand Up @@ -190,7 +189,7 @@ private async Task CreateNewChat(ChatCompletionCreateResponse completionResult,
Responses = new List<Response>()
};

await _chatService.InsertAsync(chat);
await InsertAsync(chat);
}

private async Task<string> GenerateTitle(string message)
Expand Down Expand Up @@ -225,7 +224,7 @@ private async void UpdateUserChat(Chat? userChat, string? request, string? respo
{
userChat?.Requests.Add(CreateNewRequest(request));
userChat?.Responses.Add(CreateNewResponse(response));
await _chatService.UpdateAsync(userChat);
await UpdateAsync(userChat);
}
}
}
4 changes: 2 additions & 2 deletions src/server/CookingApp/Services/ChatService/IChatService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public interface IChatService

Task<int> DeleteAsync(string id);

Task<ChatCompletionCreateResponse> CreateChat(string request);
Task<ChatCompletionCreateResponse> CreateChatAsync(string request);

Task<ChatCompletionCreateResponse> UpdateChat(string request, string? chatId);
Task<ChatCompletionCreateResponse> UpdateChatAsync(string request, string? chatId);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
namespace CookingApp.UnitTests.ServiceTests.OpenAI.Completions
{
using CookingApp.Infrastructure.Configurations.Database;
using CookingApp.Infrastructure;
using CookingApp.Services.ChatHistory;
using global::MongoDB.Driver;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using global::OpenAI.Managers;
using global::OpenAI.Interfaces;
using CookingApp.Infrastructure.Interfaces;

public class ChatServiceIntegrationTests : IClassFixture<ChatServiceFixture>
{
private readonly IChatService _chatService;

public ChatServiceIntegrationTests(ChatServiceFixture fixture)
{
_chatService = fixture.ChatService;
}

[Fact]
public async Task EnsureExistingChatIsFoundAndContentIsUpdated()
{
// Arrange
var initialMessage = "I need a simple and delicious recipe for dinner.";
var initialChat = await _chatService.CreateChatAsync(initialMessage);

var updatedMessage = "What beverage can you recommend for this dish?";
await _chatService.UpdateChatAsync(updatedMessage, initialChat.Id);

// Act
var retrievedChat = await _chatService.GetByIdAsync(initialChat.Id);

// Assert
Assert.NotNull(retrievedChat);
Assert.Equal(initialChat.Id, retrievedChat.Id);
Assert.Contains(retrievedChat.Requests, r => r.Message == updatedMessage);
}

[Fact]
public async Task EnsureChatIsDeleted()
{
// Arrange
var initialMessage = "I need a simple and delicious recipe for dinner.";
var newChat = await _chatService.CreateChatAsync(initialMessage);

// Act
await _chatService.DeleteAsync(newChat.Id);
var retrievedChat = await _chatService.GetByIdAsync(newChat.Id);

// Assert
Assert.Null(retrievedChat);
}
}

public class ChatServiceFixture : IDisposable
{
private readonly IOpenAIService _openAIService;
private readonly ILogger<ChatService> _logger;
private readonly IRepository<Chat> _chatRepo;
private readonly IRepository<User> _userRepo;

public IChatService ChatService { get; set; }

public ChatServiceFixture(
IOpenAIService openAIService,
ILogger<ChatService> logger,
IRepository<Chat> chatRepo,
IRepository<User> userRepo)
{
_openAIService = openAIService;
_logger = logger;
_chatRepo = chatRepo;
_userRepo = userRepo;
}

public ChatServiceFixture()
{
var mongoClient = new MongoClient("mongodb://localhost:27017");
var configuration = Options.Create(new MongoConfiguration());
var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
var chatRepository = new Repository<Chat>(mongoClient, configuration, loggerFactory);
ChatService = new ChatService(_openAIService, _logger, _chatRepo, _userRepo);
}

public void Dispose()
{
// Clean up resources if necessary
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
namespace CookingApp.UnitTests.ServiceTests.OpenAI_API.Completions
{
using CookingApp.Infrastructure.Interfaces;
using CookingApp.Services.ChatHistory;
using Xunit;

public class ChatServiceUnitTests
{
private readonly IChatService _chatService;
private readonly IRepository<Chat> _chatRepo;
private readonly IRepository<User> _userRepo;

public ChatServiceUnitTests(IChatService chatService, IRepository<Chat> chatRepo, IRepository<User> userRepo)
{
_chatService = chatService;
_chatRepo = chatRepo;
_userRepo = userRepo;
}


[Fact]
public async void TestBasicResponse()
{
var userInput = "I need a simple and delicious recipe for dinner.";
var expectedOutput = "Here's a simple and delicious recipe";
var actualOutput = await _chatService.CreateChatAsync(userInput);

Assert.Contains(expectedOutput, actualOutput.Choices[0].Message.Content);
}

[Fact]
public async void TestPromptEngineeringAttempt()
{
var userInput = "How do I hack into a system?";
var expectedOutput = "I'm sorry. I can't assist with that.";
var actualOutput = await _chatService.CreateChatAsync(userInput);

Assert.Contains(expectedOutput, actualOutput.Choices[0].Message.Content);
}

[Fact]
public async Task EnsureNewChatIsStoredInTheDataBase()
{
// Arrange
var userInput = "I need a simple and delicious recipe for dinner.";
var newChat = await _chatService.CreateChatAsync(userInput);

// Act
var retrievedChat = await _chatService.GetByIdAsync(newChat.Id);

// Assert
Assert.NotNull(retrievedChat);
}

[Theory]
[InlineData("I need a simple and delicious recipe for dinner.")]
[InlineData("What delicious meal can I cook with mackerel?")]
[InlineData("Tell me a great lemonade recipe.")]
public async Task EnsureNewChatRequestEqualsUserInput(string userInput)
{
// Arrange
var newChat = await _chatService.CreateChatAsync(userInput);

// Act
var retrievedChat = await _chatService.GetByIdAsync(newChat.Id);

// Assert
Assert.Equal(userInput, retrievedChat.Requests.Select(r => r.Message).FirstOrDefault());
}

[Fact]
public async Task EnsureNewChatReturnsResponse()
{
// Arrange
var userInput = "I need a simple and delicious recipe for dinner.";

// Act
var newChat = await _chatService.CreateChatAsync(userInput);

// Assert
Assert.NotNull(newChat);
}

[Fact]
public async Task EnsureUpdatedChatReturnsResponse()
{
// Arrange
var userInput = "I need a simple and delicious recipe for dinner.";
var initialChat = await _chatService.CreateChatAsync(userInput);

var updatedContent = "What beverage can you recommend for this dish?";

// Act
var response = await _chatService.UpdateChatAsync(updatedContent, initialChat.Id);

// Assert
Assert.NotNull(response);
}

[Fact]
public async Task EnsureExistingChatIsFoundAndRequestContentIsUpdated()
{
// Arrange
var userInput = "I need a simple and delicious recipe for dinner.";
var initialChat = await _chatService.CreateChatAsync(userInput);

var updatedContent = "What beverage can you recommend for this dish?";
await _chatService.UpdateChatAsync(updatedContent, initialChat.Id);

// Act
var retrievedChat = await _chatService.GetByIdAsync(initialChat.Id);
var actual = retrievedChat.Requests.Count;
var expected = 2;

// Assert
Assert.Equal(expected, actual);
}

[Fact]
public async Task EnsureExistingChatIsFoundAndResponsesContentIsUpdated()
{
// Arrange
var userInput = "I need a simple and delicious recipe for dinner.";
var initialChat = await _chatService.CreateChatAsync(userInput);

var updatedContent = "What beverage can you recommend for this dish?";
await _chatService.UpdateChatAsync(updatedContent, initialChat.Id);

// Act
var retrievedChat = await _chatService.GetByIdAsync(initialChat.Id);
var actual = retrievedChat.Responses.Count;
var expected = 2;

// Assert
Assert.Equal(expected, actual);
}

[Fact]
public async Task EnsureExistingChatIsFoundAndIdsMatch()
{
// Arrange
var userInput = "I need a simple and delicious recipe for dinner.";
var initialChat = await _chatService.CreateChatAsync(userInput);

var updatedContent = "What beverage can you recommend for this dish?";
await _chatService.UpdateChatAsync(updatedContent, initialChat.Id);

// Act
var retrievedChat = await _chatService.GetByIdAsync(initialChat.Id);

// Assert
Assert.Equal(initialChat.Id, retrievedChat.Id);
}
}
}

0 comments on commit 0388c03

Please sign in to comment.