-
Notifications
You must be signed in to change notification settings - Fork 18
test(repositories): add integration tests for Repository<T> and PlayerRepository (#461)
#463
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
186 changes: 186 additions & 0 deletions
186
test/Dotnet.Samples.AspNetCore.WebApi.Tests/Integration/PlayerRepositoryTests.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,186 @@ | ||
| using System.Data.Common; | ||
| using Dotnet.Samples.AspNetCore.WebApi.Data; | ||
| using Dotnet.Samples.AspNetCore.WebApi.Models; | ||
| using Dotnet.Samples.AspNetCore.WebApi.Repositories; | ||
| using Dotnet.Samples.AspNetCore.WebApi.Tests.Utilities; | ||
| using FluentAssertions; | ||
|
|
||
| namespace Dotnet.Samples.AspNetCore.WebApi.Tests.Integration; | ||
|
|
||
| /// <summary> | ||
| /// Integration tests for <see cref="Repository{T}"/> and <see cref="PlayerRepository"/>. | ||
| /// Each test runs against an in-memory SQLite database with the full EF Core migration | ||
| /// chain applied via <see cref="DatabaseFakes.MigrateAsync"/>, which also validates | ||
| /// that the migration chain itself is healthy as a side effect. | ||
| /// </summary> | ||
| public class PlayerRepositoryTests : IAsyncLifetime | ||
| { | ||
| private DbConnection _connection = default!; | ||
| private PlayerDbContext _dbContext = default!; | ||
| private PlayerRepository _repository = default!; | ||
|
|
||
| public async Task InitializeAsync() | ||
| { | ||
| var (connection, options) = DatabaseFakes.CreateSqliteConnection(); | ||
| _connection = connection; | ||
| _dbContext = DatabaseFakes.CreateDbContext(options); | ||
| await _dbContext.MigrateAsync(); | ||
| _repository = new PlayerRepository(_dbContext); | ||
| } | ||
|
|
||
| public async Task DisposeAsync() | ||
| { | ||
| await _dbContext.DisposeAsync(); | ||
| await _connection.DisposeAsync(); | ||
| } | ||
|
|
||
| /* ------------------------------------------------------------------------- | ||
| * GetAllAsync | ||
| * ---------------------------------------------------------------------- */ | ||
|
|
||
| [Fact] | ||
| [Trait("Category", "Integration")] | ||
| public async Task GetAllAsync_WhenCalled_ReturnsAllSeededPlayers() | ||
| { | ||
| // Act | ||
| var players = await _repository.GetAllAsync(); | ||
|
|
||
| // Assert | ||
| players.Should().HaveCount(26); | ||
| _dbContext.ChangeTracker.Entries<Player>().Should().BeEmpty(); | ||
| } | ||
|
|
||
| /* ------------------------------------------------------------------------- | ||
| * FindByIdAsync | ||
| * ---------------------------------------------------------------------- */ | ||
|
|
||
| [Fact] | ||
| [Trait("Category", "Integration")] | ||
| public async Task FindByIdAsync_ExistingId_ReturnsPlayer() | ||
| { | ||
| // Arrange — resolve a real ID from the seeded database | ||
| var seeded = await _repository.GetAllAsync(); | ||
| var existingId = seeded[0].Id; | ||
|
|
||
| // Act | ||
| var player = await _repository.FindByIdAsync(existingId); | ||
|
|
||
| // Assert | ||
| player.Should().NotBeNull(); | ||
| player!.Id.Should().Be(existingId); | ||
| } | ||
|
|
||
| [Fact] | ||
| [Trait("Category", "Integration")] | ||
| public async Task FindByIdAsync_UnknownId_ReturnsNull() | ||
| { | ||
| // Act | ||
| var player = await _repository.FindByIdAsync(Guid.NewGuid()); | ||
|
|
||
| // Assert | ||
| player.Should().BeNull(); | ||
| } | ||
|
|
||
| /* ------------------------------------------------------------------------- | ||
| * RemoveAsync | ||
| * ---------------------------------------------------------------------- */ | ||
|
|
||
| [Fact] | ||
| [Trait("Category", "Integration")] | ||
| public async Task RemoveAsync_ExistingEntity_RemovesFromDatabase() | ||
| { | ||
| // Arrange | ||
| var seeded = await _repository.GetAllAsync(); | ||
| var existingId = seeded[0].Id; | ||
|
|
||
| // Act | ||
| await _repository.RemoveAsync(existingId); | ||
|
|
||
| // Assert | ||
| var player = await _repository.FindByIdAsync(existingId); | ||
| player.Should().BeNull(); | ||
| } | ||
|
|
||
| [Fact] | ||
| [Trait("Category", "Integration")] | ||
| public async Task RemoveAsync_UnknownId_NoExceptionThrown() | ||
| { | ||
| // Arrange | ||
| var countBefore = (await _repository.GetAllAsync()).Count; | ||
|
|
||
| // Act | ||
| var act = async () => await _repository.RemoveAsync(Guid.NewGuid()); | ||
|
|
||
| // Assert | ||
| await act.Should().NotThrowAsync(); | ||
| var countAfter = (await _repository.GetAllAsync()).Count; | ||
| countAfter.Should().Be(countBefore); | ||
| } | ||
|
|
||
| /* ------------------------------------------------------------------------- | ||
| * FindBySquadNumberAsync | ||
| * ---------------------------------------------------------------------- */ | ||
|
|
||
| [Fact] | ||
| [Trait("Category", "Integration")] | ||
| public async Task FindBySquadNumberAsync_ExistingSquadNumber_ReturnsPlayer() | ||
| { | ||
| // Arrange | ||
| var expected = PlayerFakes.MakeFromStarting11(23); | ||
|
|
||
| // Act | ||
| var player = await _repository.FindBySquadNumberAsync(expected.SquadNumber); | ||
|
|
||
| // Assert | ||
| player.Should().NotBeNull(); | ||
| player!.SquadNumber.Should().Be(expected.SquadNumber); | ||
| } | ||
|
|
||
| [Fact] | ||
| [Trait("Category", "Integration")] | ||
| public async Task FindBySquadNumberAsync_UnknownSquadNumber_ReturnsNull() | ||
| { | ||
| // Arrange — derive a squad number guaranteed not to exist in the seeded data | ||
| var seeded = await _repository.GetAllAsync(); | ||
| var unknownSquadNumber = seeded.Max(p => p.SquadNumber) + 1; | ||
|
|
||
| // Act | ||
| var player = await _repository.FindBySquadNumberAsync(unknownSquadNumber); | ||
|
|
||
| // Assert | ||
| player.Should().BeNull(); | ||
| } | ||
|
|
||
| /* ------------------------------------------------------------------------- | ||
| * SquadNumberExistsAsync | ||
| * ---------------------------------------------------------------------- */ | ||
|
|
||
| [Fact] | ||
| [Trait("Category", "Integration")] | ||
| public async Task SquadNumberExistsAsync_ExistingSquadNumber_ReturnsTrue() | ||
| { | ||
| // Arrange | ||
| var expected = PlayerFakes.MakeFromStarting11(23); | ||
|
|
||
| // Act | ||
| var exists = await _repository.SquadNumberExistsAsync(expected.SquadNumber); | ||
|
|
||
| // Assert | ||
| exists.Should().BeTrue(); | ||
| } | ||
|
|
||
| [Fact] | ||
| [Trait("Category", "Integration")] | ||
| public async Task SquadNumberExistsAsync_UnknownSquadNumber_ReturnsFalse() | ||
| { | ||
| // Arrange — derive a squad number guaranteed not to exist in the seeded data | ||
| var seeded = await _repository.GetAllAsync(); | ||
| var unknownSquadNumber = seeded.Max(p => p.SquadNumber) + 1; | ||
|
|
||
| // Act | ||
| var exists = await _repository.SquadNumberExistsAsync(unknownSquadNumber); | ||
|
|
||
| // Assert | ||
| exists.Should().BeFalse(); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.