add tests
All checks were successful
SonarQube / Build and analyze (push) Successful in 3m39s

This commit is contained in:
Leonid Pershin
2025-10-21 02:30:04 +03:00
parent 928ae0555e
commit 2a26e84100
15 changed files with 1837 additions and 61 deletions

View File

@@ -255,4 +255,328 @@ public class DatabaseInitializationServiceTests : UnitTestBase
Times.Once
);
}
[Fact]
public async Task StartAsync_WhenDatabaseExists_ShouldLogAndMigrate()
{
// Arrange
var dbPath = $"TestDb_{Guid.NewGuid()}.db";
var services = new ServiceCollection();
services.AddDbContext<ChatBotDbContext>(options =>
options.UseSqlite($"Data Source={dbPath}")
.ConfigureWarnings(w => w.Ignore(Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.PendingModelChangesWarning))
);
var serviceProvider = services.BuildServiceProvider();
var loggerMock = new Mock<ILogger<DatabaseInitializationService>>();
var service = new DatabaseInitializationService(serviceProvider, loggerMock.Object);
try
{
// Act
await service.StartAsync(CancellationToken.None);
// Assert
loggerMock.Verify(
x =>
x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>(
(v, t) => v.ToString()!.Contains("Starting database initialization")
),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
loggerMock.Verify(
x =>
x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>(
(v, t) =>
v.ToString()!
.Contains("Database initialization completed successfully")
),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
}
finally
{
// Cleanup
serviceProvider.Dispose();
GC.Collect();
GC.WaitForPendingFinalizers();
if (File.Exists(dbPath))
{
try { File.Delete(dbPath); } catch { /* Ignore cleanup errors */ }
}
}
}
[Fact]
public async Task StopAsync_WithCancellationToken_ShouldComplete()
{
// Arrange
var serviceProviderMock = new Mock<IServiceProvider>();
var loggerMock = new Mock<ILogger<DatabaseInitializationService>>();
var service = new DatabaseInitializationService(
serviceProviderMock.Object,
loggerMock.Object
);
var cts = new CancellationTokenSource();
// Act
await service.StopAsync(cts.Token);
// Assert
loggerMock.Verify(
x =>
x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>(
(v, t) => v.ToString()!.Contains("Database initialization service stopped")
),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
}
[Fact]
public async Task StopAsync_WhenCancellationRequested_ShouldStillComplete()
{
// Arrange
var serviceProviderMock = new Mock<IServiceProvider>();
var loggerMock = new Mock<ILogger<DatabaseInitializationService>>();
var service = new DatabaseInitializationService(
serviceProviderMock.Object,
loggerMock.Object
);
var cts = new CancellationTokenSource();
cts.Cancel();
// Act
await service.StopAsync(cts.Token);
// Assert
loggerMock.Verify(
x =>
x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>(
(v, t) => v.ToString()!.Contains("Database initialization service stopped")
),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
}
[Fact]
public async Task StartAsync_ShouldHandleDatabaseDoesNotExistException()
{
// Arrange
var dbPath = $"TestDb_{Guid.NewGuid()}.db";
var services = new ServiceCollection();
services.AddDbContext<ChatBotDbContext>(options =>
options.UseSqlite($"Data Source={dbPath}")
.ConfigureWarnings(w => w.Ignore(Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.PendingModelChangesWarning))
);
var serviceProvider = services.BuildServiceProvider();
var loggerMock = new Mock<ILogger<DatabaseInitializationService>>();
var service = new DatabaseInitializationService(serviceProvider, loggerMock.Object);
try
{
// Act
await service.StartAsync(CancellationToken.None);
// Assert - service should complete successfully
loggerMock.Verify(
x =>
x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>(
(v, t) =>
v.ToString()!
.Contains("Database initialization completed successfully")
),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
}
finally
{
// Cleanup
serviceProvider.Dispose();
GC.Collect();
GC.WaitForPendingFinalizers();
if (File.Exists(dbPath))
{
try { File.Delete(dbPath); } catch { /* Ignore cleanup errors */ }
}
}
}
[Fact]
public async Task StartAsync_WithValidDatabase_ShouldLogDatabaseExists()
{
// Arrange
var dbPath = $"TestDb_{Guid.NewGuid()}.db";
var services = new ServiceCollection();
services.AddDbContext<ChatBotDbContext>(options =>
options.UseSqlite($"Data Source={dbPath}")
.ConfigureWarnings(w => w.Ignore(Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.PendingModelChangesWarning))
);
var serviceProvider = services.BuildServiceProvider();
var loggerMock = new Mock<ILogger<DatabaseInitializationService>>();
var service = new DatabaseInitializationService(serviceProvider, loggerMock.Object);
try
{
// Act
await service.StartAsync(CancellationToken.None);
// Assert
loggerMock.Verify(
x =>
x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => true), // Any log message
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.AtLeastOnce
);
}
finally
{
// Cleanup
serviceProvider.Dispose();
GC.Collect();
GC.WaitForPendingFinalizers();
if (File.Exists(dbPath))
{
try { File.Delete(dbPath); } catch { /* Ignore cleanup errors */ }
}
}
}
[Fact]
public void DatabaseInitializationService_ShouldImplementIHostedService()
{
// Arrange
var serviceProviderMock = new Mock<IServiceProvider>();
var loggerMock = new Mock<ILogger<DatabaseInitializationService>>();
// Act
var service = new DatabaseInitializationService(
serviceProviderMock.Object,
loggerMock.Object
);
// Assert
service.Should().BeAssignableTo<Microsoft.Extensions.Hosting.IHostedService>();
}
[Fact]
public async Task StartAsync_MultipleCallsInSequence_ShouldWork()
{
// Arrange
var dbPath = $"TestDb_{Guid.NewGuid()}.db";
var services = new ServiceCollection();
services.AddDbContext<ChatBotDbContext>(options =>
options.UseSqlite($"Data Source={dbPath}")
.ConfigureWarnings(w => w.Ignore(Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.PendingModelChangesWarning))
);
var serviceProvider = services.BuildServiceProvider();
var loggerMock = new Mock<ILogger<DatabaseInitializationService>>();
var service = new DatabaseInitializationService(serviceProvider, loggerMock.Object);
try
{
// Act
await service.StartAsync(CancellationToken.None);
await service.StopAsync(CancellationToken.None);
// Assert - should complete without exceptions
loggerMock.Verify(
x =>
x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>(
(v, t) =>
v.ToString()!
.Contains("Database initialization completed successfully")
),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
}
finally
{
// Cleanup
serviceProvider.Dispose();
GC.Collect();
GC.WaitForPendingFinalizers();
if (File.Exists(dbPath))
{
try { File.Delete(dbPath); } catch { /* Ignore cleanup errors */ }
}
}
}
[Fact]
public async Task StopAsync_WithoutStartAsync_ShouldComplete()
{
// Arrange
var serviceProviderMock = new Mock<IServiceProvider>();
var loggerMock = new Mock<ILogger<DatabaseInitializationService>>();
var service = new DatabaseInitializationService(
serviceProviderMock.Object,
loggerMock.Object
);
// Act
await service.StopAsync(CancellationToken.None);
// Assert - should complete without exceptions
loggerMock.Verify(
x =>
x.Log(
LogLevel.Information,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>(
(v, t) => v.ToString()!.Contains("Database initialization service stopped")
),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
),
Times.Once
);
}
}