tests: dispose of resources, add tests for maintainer, and clean up mock names

This commit is contained in:
Stevan Freeborn
2024-08-25 12:22:40 -05:00
parent 14e35670a5
commit 674712db9d
10 changed files with 190 additions and 33 deletions
@@ -1,6 +1,6 @@
namespace SanctionsSearch.Worker.Tests.Integration; namespace SanctionsSearch.Worker.Tests.Integration;
public class DatabaseMaintainerTests : DatabaseTest public class DatabaseMaintainerTests : DatabaseTest, IDisposable
{ {
private const string TestSdnCsv = """ private const string TestSdnCsv = """
6906,"AL-IRAQI, Abd al-Hadi","individual","SDGT",-0- ,-0- ,-0- ,-0- ,-0- ,-0- ,-0- ,"DOB 1961; POB Mosul, Iraq; nationality Iraq; Gender Male." 6906,"AL-IRAQI, Abd al-Hadi","individual","SDGT",-0- ,-0- ,-0- ,-0- ,-0- ,-0- ,-0- ,"DOB 1961; POB Mosul, Iraq; nationality Iraq; Gender Male."
@@ -279,4 +279,12 @@ public class DatabaseMaintainerTests : DatabaseTest
} }
}); });
} }
public void Dispose()
{
_databaseMaintainer.Dispose();
_mockHttp.Dispose();
GC.SuppressFinalize(this);
}
} }
@@ -25,6 +25,7 @@ public class DatabaseTest : IAsyncLifetime
public virtual async Task DisposeAsync() public virtual async Task DisposeAsync()
{ {
await _appDbContext.DisposeAsync(); await _appDbContext.DisposeAsync();
_loggerFactory.Dispose();
SqliteConnection.ClearAllPools(); SqliteConnection.ClearAllPools();
@@ -2,14 +2,14 @@ namespace SanctionsSearch.Worker.Tests.Unit;
public class AddressRepositoryTests public class AddressRepositoryTests
{ {
private readonly Mock<DbContext> _context = new(); private readonly Mock<DbContext> _contextMock = new();
private readonly Mock<ILogger<AddressRepository>> _logger = new(); private readonly Mock<ILogger<AddressRepository>> _loggerMock = new();
private readonly AddressFaker _faker = new(); private readonly AddressFaker _faker = new();
private readonly AddressRepository _repository; private readonly AddressRepository _repository;
public AddressRepositoryTests() public AddressRepositoryTests()
{ {
_repository = new AddressRepository(_context.Object, _logger.Object); _repository = new AddressRepository(_contextMock.Object, _loggerMock.Object);
} }
[Fact] [Fact]
@@ -22,13 +22,13 @@ public class AddressRepositoryTests
.Setup(x => x.FindAsync(entity.Id)) .Setup(x => x.FindAsync(entity.Id))
.Throws<Exception>(); .Throws<Exception>();
_context _contextMock
.Setup(x => x.Set<Address>()) .Setup(x => x.Set<Address>())
.Returns(mockSet.Object); .Returns(mockSet.Object);
await _repository.Upsert(entity); await _repository.Upsert(entity);
_logger.Verify( _loggerMock.Verify(
x => x.Log( x => x.Log(
LogLevel.Error, LogLevel.Error,
It.IsAny<EventId>(), It.IsAny<EventId>(),
@@ -42,7 +42,7 @@ public class AddressRepositoryTests
[Fact] [Fact]
public async Task Find_WhenExceptionIsThrown_ItShouldReturnEmptyListAndLogError() public async Task Find_WhenExceptionIsThrown_ItShouldReturnEmptyListAndLogError()
{ {
_context _contextMock
.Setup(x => x.Set<Address>()) .Setup(x => x.Set<Address>())
.Throws<Exception>(); .Throws<Exception>();
@@ -50,7 +50,7 @@ public class AddressRepositoryTests
result.Should().BeEmpty(); result.Should().BeEmpty();
_logger.Verify( _loggerMock.Verify(
x => x.Log( x => x.Log(
LogLevel.Error, LogLevel.Error,
It.IsAny<EventId>(), It.IsAny<EventId>(),
@@ -2,14 +2,14 @@ namespace SanctionsSearch.Worker.Tests.Unit;
public class AliasRepositoryTests public class AliasRepositoryTests
{ {
private readonly Mock<DbContext> _context = new(); private readonly Mock<DbContext> _contextMock = new();
private readonly Mock<ILogger<AliasRepository>> _logger = new(); private readonly Mock<ILogger<AliasRepository>> _loggerMock = new();
private readonly AliasFaker _faker = new(); private readonly AliasFaker _faker = new();
private readonly AliasRepository _repository; private readonly AliasRepository _repository;
public AliasRepositoryTests() public AliasRepositoryTests()
{ {
_repository = new AliasRepository(_context.Object, _logger.Object); _repository = new AliasRepository(_contextMock.Object, _loggerMock.Object);
} }
[Fact] [Fact]
@@ -22,13 +22,13 @@ public class AliasRepositoryTests
.Setup(x => x.FindAsync(entity.Id)) .Setup(x => x.FindAsync(entity.Id))
.Throws<Exception>(); .Throws<Exception>();
_context _contextMock
.Setup(x => x.Set<Alias>()) .Setup(x => x.Set<Alias>())
.Returns(mockSet.Object); .Returns(mockSet.Object);
await _repository.Upsert(entity); await _repository.Upsert(entity);
_logger.Verify( _loggerMock.Verify(
x => x.Log( x => x.Log(
LogLevel.Error, LogLevel.Error,
It.IsAny<EventId>(), It.IsAny<EventId>(),
@@ -42,7 +42,7 @@ public class AliasRepositoryTests
[Fact] [Fact]
public async Task Find_WhenExceptionIsThrown_ItShouldReturnEmptyListAndLogError() public async Task Find_WhenExceptionIsThrown_ItShouldReturnEmptyListAndLogError()
{ {
_context _contextMock
.Setup(x => x.Set<Alias>()) .Setup(x => x.Set<Alias>())
.Throws<Exception>(); .Throws<Exception>();
@@ -50,7 +50,7 @@ public class AliasRepositoryTests
result.Should().BeEmpty(); result.Should().BeEmpty();
_logger.Verify( _loggerMock.Verify(
x => x.Log( x => x.Log(
LogLevel.Error, LogLevel.Error,
It.IsAny<EventId>(), It.IsAny<EventId>(),
@@ -2,14 +2,14 @@ namespace SanctionsSearch.Worker.Tests.Unit;
public class CommentRepositoryTests public class CommentRepositoryTests
{ {
private readonly Mock<DbContext> _context = new(); private readonly Mock<DbContext> _contextMock = new();
private readonly Mock<ILogger<CommentRepository>> _logger = new(); private readonly Mock<ILogger<CommentRepository>> _loggerMock = new();
private readonly CommentFaker _faker = new(); private readonly CommentFaker _faker = new();
private readonly CommentRepository _repository; private readonly CommentRepository _repository;
public CommentRepositoryTests() public CommentRepositoryTests()
{ {
_repository = new CommentRepository(_context.Object, _logger.Object); _repository = new CommentRepository(_contextMock.Object, _loggerMock.Object);
} }
[Fact] [Fact]
@@ -22,13 +22,13 @@ public class CommentRepositoryTests
.Setup(x => x.FindAsync(entity.Id)) .Setup(x => x.FindAsync(entity.Id))
.Throws<Exception>(); .Throws<Exception>();
_context _contextMock
.Setup(x => x.Set<Comment>()) .Setup(x => x.Set<Comment>())
.Returns(mockSet.Object); .Returns(mockSet.Object);
await _repository.Upsert(entity); await _repository.Upsert(entity);
_logger.Verify( _loggerMock.Verify(
x => x.Log( x => x.Log(
LogLevel.Error, LogLevel.Error,
It.IsAny<EventId>(), It.IsAny<EventId>(),
@@ -42,7 +42,7 @@ public class CommentRepositoryTests
[Fact] [Fact]
public async Task Find_WhenExceptionIsThrown_ItShouldReturnEmptyListAndLogError() public async Task Find_WhenExceptionIsThrown_ItShouldReturnEmptyListAndLogError()
{ {
_context _contextMock
.Setup(x => x.Set<Comment>()) .Setup(x => x.Set<Comment>())
.Throws<Exception>(); .Throws<Exception>();
@@ -50,7 +50,7 @@ public class CommentRepositoryTests
result.Should().BeEmpty(); result.Should().BeEmpty();
_logger.Verify( _loggerMock.Verify(
x => x.Log( x => x.Log(
LogLevel.Error, LogLevel.Error,
It.IsAny<EventId>(), It.IsAny<EventId>(),
@@ -0,0 +1,103 @@
using FluentResults;
namespace SanctionsSearch.Worker.Tests.Unit;
public class DatabaseMaintainerTests : IDisposable
{
private readonly Mock<IUnitOfWork> _unitOfWorkMock = new();
private readonly Mock<IOfacFileService> _ofacFileServiceMock = new();
private readonly Mock<ILogger<DatabaseMaintainer>> _loggerMock = new();
private readonly DatabaseMaintainer _databaseMaintainer;
public DatabaseMaintainerTests()
{
_databaseMaintainer = new(_unitOfWorkMock.Object, _ofacFileServiceMock.Object, _loggerMock.Object);
}
[Fact]
public async Task BuildSdnTableAsync_WhenUnableToRetrieveCsvFile_ItShouldLogError()
{
_ofacFileServiceMock
.Setup(x => x.GetSdnFileAsync())
.ReturnsAsync(Result.Fail<Stream>("Error"));
await _databaseMaintainer.BuildSdnTableAsync();
_loggerMock.Verify(
x => x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
)
);
}
[Fact]
public async Task BuildAddressTableAsync_WhenUnableToRetrieveCsvFile_ItShouldLogError()
{
_ofacFileServiceMock
.Setup(x => x.GetAddressFileAsync())
.ReturnsAsync(Result.Fail<Stream>("Error"));
await _databaseMaintainer.BuildAddressTableAsync();
_loggerMock.Verify(
x => x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
)
);
}
[Fact]
public async Task BuildAliasTableAsync_WhenUnableToRetrieveCsvFile_ItShouldLogError()
{
_ofacFileServiceMock
.Setup(x => x.GetAltNamesFileAsync())
.ReturnsAsync(Result.Fail<Stream>("Error"));
await _databaseMaintainer.BuiltAliasTableAsync();
_loggerMock.Verify(
x => x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
)
);
}
[Fact]
public async Task BuildCommentsTableAsync_WhenUnableToRetrieveCsvFile_ItShouldLogError()
{
_ofacFileServiceMock
.Setup(x => x.GetCommentsFileAsync())
.ReturnsAsync(Result.Fail<Stream>("Error"));
await _databaseMaintainer.BuildCommentTableAsync();
_loggerMock.Verify(
x => x.Log(
LogLevel.Error,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()
)
);
}
public void Dispose()
{
_databaseMaintainer.Dispose();
GC.SuppressFinalize(this);
}
}
@@ -2,13 +2,13 @@ namespace SanctionsSearch.Worker.Tests.Unit;
public class EfUnitOfWorkTests public class EfUnitOfWorkTests
{ {
private readonly Mock<DbContext> _context = new(); private readonly Mock<DbContext> _contextMock = new();
private readonly Mock<ILoggerFactory> _loggerFactory = new(); private readonly Mock<ILoggerFactory> _loggerFactoryMock = new();
private readonly EfUnitOfWork _unitOfWork; private readonly EfUnitOfWork _unitOfWork;
public EfUnitOfWorkTests() public EfUnitOfWorkTests()
{ {
_unitOfWork = new(_context.Object, _loggerFactory.Object); _unitOfWork = new(_contextMock.Object, _loggerFactoryMock.Object);
} }
[Fact] [Fact]
@@ -34,4 +34,40 @@ public class EfUnitOfWorkTests
{ {
_unitOfWork.Comments.Should().BeOfType<CommentRepository>(); _unitOfWork.Comments.Should().BeOfType<CommentRepository>();
} }
[Fact]
public void SaveChangesAsync_WhenADatabaseUpdateExceptionIsThrown_ItShouldBeCaughtAndLogged()
{
_contextMock
.Setup(x => x.SaveChangesAsync(It.IsAny<CancellationToken>()))
.ThrowsAsync(new DbUpdateException());
var action = _unitOfWork.SaveChangesAsync;
action.Should().NotThrowAsync();
}
[Fact]
public void SaveChangesAsync_WhenExceptionIsThrown_ItShouldNotBeCaught()
{
_contextMock
.Setup(x => x.SaveChangesAsync(It.IsAny<CancellationToken>()))
.ThrowsAsync(new Exception());
var action = _unitOfWork.SaveChangesAsync;
action.Should().ThrowAsync<Exception>();
}
[Fact]
public void DisposeAsync_WhenExceptionIsThrown_ItShouldBeCaught()
{
_contextMock
.Setup(x => x.DisposeAsync())
.Throws(new Exception());
var action = _unitOfWork.DisposeAsync;
action.Should().NotThrow();
}
} }
@@ -1,6 +1,6 @@
namespace SanctionsSearch.Worker.Tests.Unit; namespace SanctionsSearch.Worker.Tests.Unit;
public class OfacFileServiceTests public class OfacFileServiceTests : IDisposable
{ {
private const string TestCsv = "Name,Address\nJohn Doe,123 Main St\n"; private const string TestCsv = "Name,Address\nJohn Doe,123 Main St\n";
private static Stream TestStream => new MemoryStream(Encoding.UTF8.GetBytes(TestCsv)); private static Stream TestStream => new MemoryStream(Encoding.UTF8.GetBytes(TestCsv));
@@ -286,4 +286,11 @@ public class OfacFileServiceTests
result.IsFailed.Should().BeTrue(); result.IsFailed.Should().BeTrue();
} }
public void Dispose()
{
_mockHttp.Dispose();
GC.SuppressFinalize(this);
}
} }
@@ -2,14 +2,14 @@ namespace SanctionsSearch.Worker.Tests.Unit;
public class SdnRepositoryTests public class SdnRepositoryTests
{ {
private readonly Mock<DbContext> _context = new(); private readonly Mock<DbContext> _contextMock = new();
private readonly Mock<ILogger<SdnRepository>> _logger = new(); private readonly Mock<ILogger<SdnRepository>> _loggerMock = new();
private readonly SdnFaker _faker = new(); private readonly SdnFaker _faker = new();
private readonly SdnRepository _repository; private readonly SdnRepository _repository;
public SdnRepositoryTests() public SdnRepositoryTests()
{ {
_repository = new SdnRepository(_context.Object, _logger.Object); _repository = new SdnRepository(_contextMock.Object, _loggerMock.Object);
} }
[Fact] [Fact]
@@ -22,13 +22,13 @@ public class SdnRepositoryTests
.Setup(x => x.FindAsync(entity.Id)) .Setup(x => x.FindAsync(entity.Id))
.Throws<Exception>(); .Throws<Exception>();
_context _contextMock
.Setup(x => x.Set<Sdn>()) .Setup(x => x.Set<Sdn>())
.Returns(mockSet.Object); .Returns(mockSet.Object);
await _repository.Upsert(entity); await _repository.Upsert(entity);
_logger.Verify( _loggerMock.Verify(
x => x.Log( x => x.Log(
LogLevel.Error, LogLevel.Error,
It.IsAny<EventId>(), It.IsAny<EventId>(),
@@ -42,7 +42,7 @@ public class SdnRepositoryTests
[Fact] [Fact]
public async Task Find_WhenExceptionIsThrown_ItShouldReturnEmptyListAndLogError() public async Task Find_WhenExceptionIsThrown_ItShouldReturnEmptyListAndLogError()
{ {
_context _contextMock
.Setup(x => x.Set<Sdn>()) .Setup(x => x.Set<Sdn>())
.Throws<Exception>(); .Throws<Exception>();
@@ -50,7 +50,7 @@ public class SdnRepositoryTests
result.Should().BeEmpty(); result.Should().BeEmpty();
_logger.Verify( _loggerMock.Verify(
x => x.Log( x => x.Log(
LogLevel.Error, LogLevel.Error,
It.IsAny<EventId>(), It.IsAny<EventId>(),
@@ -19,3 +19,5 @@ global using SanctionsSearch.Worker.Options;
global using SanctionsSearch.Worker.Persistence; global using SanctionsSearch.Worker.Persistence;
global using SanctionsSearch.Worker.Services; global using SanctionsSearch.Worker.Services;
global using SanctionsSearch.Worker.Tests.Faker; global using SanctionsSearch.Worker.Tests.Faker;
global using SanctionsSearch.Worker.Interfaces;