using JdeScoping.DataAccess.Exceptions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Shouldly;
using Xunit;
namespace JdeScoping.DataAccess.Tests;
///
/// Unit tests for DbConnectionFactory.
///
public class DbConnectionFactoryTests
{
private readonly IConfiguration _configuration;
private readonly ILogger _logger;
public DbConnectionFactoryTests()
{
_configuration = Substitute.For();
_logger = Substitute.For>();
}
#region Constructor Tests
[Fact]
public void Constructor_NullConfiguration_ThrowsArgumentNullException()
{
// Act & Assert
Should.Throw(() => new DbConnectionFactory(null!, _logger))
.ParamName.ShouldBe("configuration");
}
[Fact]
public void Constructor_NullLogger_ThrowsArgumentNullException()
{
// Act & Assert
Should.Throw(() => new DbConnectionFactory(_configuration, null!))
.ParamName.ShouldBe("logger");
}
[Fact]
public void Constructor_ValidParameters_CreatesInstance()
{
// Act
var factory = new DbConnectionFactory(_configuration, _logger);
// Assert
factory.ShouldNotBeNull();
}
#endregion
#region CreateLotFinderConnectionAsync Tests
[Fact]
public async Task CreateLotFinderConnectionAsync_MissingConnectionString_ThrowsConnectionException()
{
// Arrange
_configuration.GetConnectionString("LotFinderDB").Returns((string?)null);
var factory = new DbConnectionFactory(_configuration, _logger);
// Act & Assert
var ex = await Should.ThrowAsync(
async () => await factory.CreateLotFinderConnectionAsync());
ex.DataSource.ShouldBe("LotFinderDB");
ex.Message.ShouldContain("Connection string not found");
}
[Fact]
public async Task CreateLotFinderConnectionAsync_EmptyConnectionString_ThrowsConnectionException()
{
// Arrange
_configuration.GetConnectionString("LotFinderDB").Returns(string.Empty);
var factory = new DbConnectionFactory(_configuration, _logger);
// Act & Assert
var ex = await Should.ThrowAsync(
async () => await factory.CreateLotFinderConnectionAsync());
ex.DataSource.ShouldBe("LotFinderDB");
ex.Message.ShouldContain("Connection string not found");
}
[Fact]
public async Task CreateLotFinderConnectionAsync_InvalidConnectionString_ThrowsConnectionException()
{
// Arrange
_configuration.GetConnectionString("LotFinderDB").Returns("Invalid connection string");
var factory = new DbConnectionFactory(_configuration, _logger);
// Act & Assert
var ex = await Should.ThrowAsync(
async () => await factory.CreateLotFinderConnectionAsync());
ex.DataSource.ShouldBe("LotFinderDB");
ex.Message.ShouldContain("Failed to open connection");
ex.InnerException.ShouldNotBeNull();
}
[Fact]
public async Task CreateLotFinderConnectionAsync_CancellationRequested_ThrowsOperationCanceledException()
{
// Arrange
_configuration.GetConnectionString("LotFinderDB").Returns("Server=test;Database=test;");
var factory = new DbConnectionFactory(_configuration, _logger);
using var cts = new CancellationTokenSource();
cts.Cancel();
// Act & Assert
await Should.ThrowAsync(
async () => await factory.CreateLotFinderConnectionAsync(cts.Token));
}
#endregion
#region CreateJdeConnectionAsync Tests
[Fact]
public async Task CreateJdeConnectionAsync_MissingConnectionString_ThrowsConnectionException()
{
// Arrange
_configuration.GetConnectionString("JDE").Returns((string?)null);
var factory = new DbConnectionFactory(_configuration, _logger);
// Act & Assert
var ex = await Should.ThrowAsync(
async () => await factory.CreateJdeConnectionAsync());
ex.DataSource.ShouldBe("JDE");
ex.Message.ShouldContain("Connection string not found");
}
[Fact]
public async Task CreateJdeConnectionAsync_InvalidConnectionString_ThrowsConnectionException()
{
// Arrange
_configuration.GetConnectionString("JDE").Returns("Invalid oracle connection");
var factory = new DbConnectionFactory(_configuration, _logger);
// Act & Assert
var ex = await Should.ThrowAsync(
async () => await factory.CreateJdeConnectionAsync());
ex.DataSource.ShouldBe("JDE");
ex.Message.ShouldContain("Failed to open connection");
}
#endregion
#region CreateJdeStageConnectionAsync Tests
[Fact]
public async Task CreateJdeStageConnectionAsync_MissingConnectionString_ThrowsConnectionException()
{
// Arrange
_configuration.GetConnectionString("JDEStage").Returns((string?)null);
var factory = new DbConnectionFactory(_configuration, _logger);
// Act & Assert
var ex = await Should.ThrowAsync(
async () => await factory.CreateJdeStageConnectionAsync());
ex.DataSource.ShouldBe("JDEStage");
ex.Message.ShouldContain("Connection string not found");
}
#endregion
#region CreateCmsConnectionAsync Tests
[Fact]
public async Task CreateCmsConnectionAsync_MissingConnectionString_ThrowsConnectionException()
{
// Arrange
_configuration.GetConnectionString("CMS").Returns((string?)null);
var factory = new DbConnectionFactory(_configuration, _logger);
// Act & Assert
var ex = await Should.ThrowAsync(
async () => await factory.CreateCmsConnectionAsync());
ex.DataSource.ShouldBe("CMS");
ex.Message.ShouldContain("Connection string not found");
}
[Fact]
public async Task CreateCmsConnectionAsync_InvalidConnectionString_ThrowsConnectionException()
{
// Arrange
_configuration.GetConnectionString("CMS").Returns("Invalid oracle connection");
var factory = new DbConnectionFactory(_configuration, _logger);
// Act & Assert
var ex = await Should.ThrowAsync(
async () => await factory.CreateCmsConnectionAsync());
ex.DataSource.ShouldBe("CMS");
ex.Message.ShouldContain("Failed to open connection");
}
#endregion
#region Logging Tests
[Fact]
public async Task CreateLotFinderConnectionAsync_InvalidConnection_LogsError()
{
// Arrange
_configuration.GetConnectionString("LotFinderDB").Returns("Invalid connection string");
var factory = new DbConnectionFactory(_configuration, _logger);
// Act
try
{
await factory.CreateLotFinderConnectionAsync();
}
catch (ConnectionException)
{
// Expected
}
// Assert - verify error logging was called (at least once - there may also be debug logs)
_logger.Received().Log(
LogLevel.Error,
Arg.Any(),
Arg.Any