Skip to content

Commit

Permalink
Merge pull request #7 from Felix-CodingClimber/dev-felix
Browse files Browse the repository at this point in the history
Finished first tests for Repository CreateAsync and UpdateAsync.
  • Loading branch information
Felix-CodingClimber authored Jan 15, 2024
2 parents e5144c7 + 0c76da7 commit 6777ed0
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 55 deletions.
4 changes: 2 additions & 2 deletions src/DotNetElements.Core/Core/Result/CrudResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ public static CrudResult DuplicateEntry<TValue>(TValue duplicateValue)

public static CrudResult NotFound<TKey>(TKey id)
where TKey : notnull
=> new CrudResult(true, CrudError.DuplicateEntry, id.ToString());
=> new CrudResult(true, CrudError.NotFound, id.ToString());

public static CrudResult ConcurrencyConflict()
=> new CrudResult(true, CrudError.DuplicateEntry, "Entry was changed, check updated values.");
=> new CrudResult(true, CrudError.ConcurrencyConflict, "Entry was changed, check updated values.");

/// <summary>
/// Create a successful result
Expand Down
34 changes: 0 additions & 34 deletions test/DotNetElements.Core.Test/ReadOnlyRespositoryTest.cs

This file was deleted.

146 changes: 146 additions & 0 deletions test/DotNetElements.Core.Test/RespositoryTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
using DotNetElements.Core.Test.TestData;

namespace DotNetElements.Core.Test;

[TestClass]
public class ReadOnlyRepositoryTest
{
[TestMethod]
public async Task CreateAsync_AuditedEntity_DbHasValidEntityWithId()
{
using FakeRepositoryFactory<TestDbContext, FakeTagRepository, Tag, Guid> factory = new();

// Create entity
using (FakeTagRepository tagRepo = factory.CreateRepository())
{
CrudResult<Tag> result = await tagRepo.CreateAsync(FakeEntities.TagOne);

result.IsOk.Should().BeTrue();

result.Value.Should().BeEquivalentTo(FakeEntities.TagOne, options => options
.Excluding(entity => entity.Id)
.Excluding(entity => entity.CreatorId)
.Excluding(entity => entity.CreationTime));

result.Value.Id.Should().NotBeEmpty();
result.Value.CreatorId.Should().Be(factory.UserProvider.GetCurrentUserId());
result.Value.CreationTime.Should().Be(factory.TimeProvider.GetUtcNow());
}

// Assert creation result
using (FakeTagRepository tagRepo = factory.CreateRepository())
{
IReadOnlyList<Tag> tagsFromDb = await tagRepo.GetAllAsync();

tagsFromDb.Count.Should().Be(1);

tagsFromDb[0].Should().BeEquivalentTo(FakeEntities.TagOne, options => options
.Excluding(entity => entity.Id)
.Excluding(entity => entity.CreatorId)
.Excluding(entity => entity.CreationTime));

tagsFromDb[0].Id.Should().NotBeEmpty();
tagsFromDb[0].CreatorId.Should().Be(factory.UserProvider.GetCurrentUserId());
tagsFromDb[0].CreationTime.Should().Be(factory.TimeProvider.GetUtcNow());
}
}

[TestMethod]
public async Task UpdateAsync_AuditedEntity_DbHasEntityWithUpdatedValues()
{
using FakeRepositoryFactory<TestDbContext, FakeTagRepository, Tag, Guid> factory = new();

// Create entity
using (FakeTagRepository tagRepo = factory.CreateRepository())
{
await tagRepo.CreateAsync(FakeEntities.TagOne);
}

// Update entity
Tag? tagBeforeUpdate = null;
const string updatedLabelValue = "Updated Label";
DateTimeOffset utcUpdateTime = factory.TimeProvider.GetUtcNow().AddDays(1);
Guid updateUserId = FakeCurrentUserProvider.FakeUserIdTwo;

using (FakeTagRepository tagRepo = factory.CreateRepository())
{
IReadOnlyList<Tag> tagsFromDb = await tagRepo.GetAllAsync();

tagsFromDb.Count.Should().Be(1);
tagBeforeUpdate = tagsFromDb[0];

// Update value
EditTagModel editTagModel = new(tagBeforeUpdate.MapToModel());
editTagModel.Label = updatedLabelValue;

// Set new time and userId
factory.TimeProvider.SetUtcNow(utcUpdateTime);
factory.UserProvider.SetCurrentUserId(updateUserId);

CrudResult<Tag> result = await tagRepo.UpdateAsync<Tag, EditTagModel>(editTagModel.Id, editTagModel);

// todo valide result here (see CreateAsync Test)
}

// Assert update result
using (FakeTagRepository tagRepo = factory.CreateRepository())
{
IReadOnlyList<Tag> tagsFromDb = await tagRepo.GetAllAsync();

tagsFromDb[0].Should().BeEquivalentTo(tagBeforeUpdate, options => options
.Excluding(entity => entity.Label)
.Excluding(entity => entity.LastModifierId)
.Excluding(entity => entity.LastModificationTime)
.Excluding(entity => entity.Version));

tagsFromDb[0].Label.Should().Be(updatedLabelValue);
tagsFromDb[0].LastModifierId.Should().Be(updateUserId);
tagsFromDb[0].LastModificationTime.Should().Be(utcUpdateTime);
tagsFromDb[0].Version.Should().NotBe(tagBeforeUpdate.Version);
}
}

[TestMethod]
public async Task UpdateAsync_VersionedEntity_ReturnsCrudErrorConcurrencyConflict()
{
using FakeRepositoryFactory<TestDbContext, FakeTagRepository, Tag, Guid> factory = new();

// Create entity
using (FakeTagRepository tagRepo = factory.CreateRepository())
{
await tagRepo.CreateAsync(FakeEntities.TagOne);
}

// Get entity from user 1
IReadOnlyList<Tag> tagsForUser1;
using (FakeTagRepository tagRepo = factory.CreateRepository())
{
tagsForUser1 = await tagRepo.GetAllAsync();
}

// Update entity from user 2
using (FakeTagRepository tagRepo = factory.CreateRepository())
{
IReadOnlyList<Tag> tagsFromDb = await tagRepo.GetAllAsync();

// Update value
EditTagModel editTagModel = new(tagsFromDb[0].MapToModel());
editTagModel.Label = "Updated Label User 2";

await tagRepo.UpdateAsync<Tag, EditTagModel>(editTagModel.Id, editTagModel);
}

// Assert update fails for user 1
using (FakeTagRepository tagRepo = factory.CreateRepository())
{
// Update value
EditTagModel editTagModel = new(tagsForUser1[0].MapToModel());
editTagModel.Label = "Updated Label User 1";

CrudResult<Tag> result = await tagRepo.UpdateAsync<Tag, EditTagModel>(editTagModel.Id, editTagModel);

result.IsFail.Should().BeTrue();
result.Error.Should().Be(CrudError.ConcurrencyConflict);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,4 @@ public FakeTagRepository(TestDbContext dbContext, ICurrentUserProvider currentUs
: base(dbContext, currentUserProvider, timeProvider)
{
}

public FakeTagRepository(TestDbContext dbContext)
: base(dbContext)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ internal class FakeCurrentUserProvider : ICurrentUserProvider
public static readonly Guid FakeUserIdOne = new Guid("DC0BA927-FBAE-4DCA-8BAE-C1C70CBB948D");
public static readonly Guid FakeUserIdTwo = new Guid("65FA2034-6544-43E3-AF5C-DF311AE1B076");

private Guid currentUser = FakeUserIdOne;
public static Guid DefaultUserId => FakeUserIdOne;

public void SetCurrentUserId(Guid user) => currentUser = user;
private Guid currentUser = DefaultUserId;

public void SetCurrentUserId(Guid userId) => currentUser = userId;

public Guid GetCurrentUserId() => currentUser;
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
using Microsoft.Extensions.Time.Testing;

namespace DotNetElements.Core.Test.Utils;
namespace DotNetElements.Core.Test.Utils;

internal class FakeRepository<TDbContext, TEntity, TKey> : Repository<TDbContext, TEntity, TKey>, IDisposable
where TDbContext : DbContext
where TEntity : Entity<TKey>
where TKey : notnull
{
public FakeRepository(TDbContext dbContext) : base(
dbContext,
new FakeCurrentUserProvider(),
new FakeTimeProvider())
{
}

public FakeRepository(TDbContext dbContext, ICurrentUserProvider currentUserProvider, TimeProvider timeProvider) : base(
dbContext,
currentUserProvider,
Expand Down
12 changes: 10 additions & 2 deletions test/DotNetElements.Core.Test/Utils/FakeRepositoryFactory.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
namespace DotNetElements.Core.Test.Utils;
using Microsoft.Extensions.Time.Testing;

namespace DotNetElements.Core.Test.Utils;

internal sealed class FakeRepositoryFactory<TDbContext, TRepository, TEntity, TKey> : IDisposable
where TDbContext : DbContext
where TRepository : FakeRepository<TDbContext, TEntity, TKey>
where TEntity : Entity<TKey>
where TKey : notnull
{
public readonly FakeCurrentUserProvider UserProvider = new();
public readonly FakeTimeProvider TimeProvider = new();

private readonly FakeDbContextFactory<TDbContext> dbContextFactory = new();

public TRepository CreateRepository()
{
return (TRepository)Activator.CreateInstance(typeof(TRepository), dbContextFactory.CreateContext())!;
return (TRepository)Activator.CreateInstance(typeof(TRepository),
dbContextFactory.CreateContext(),
UserProvider,
TimeProvider)!;
}

public void Dispose()
Expand Down

0 comments on commit 6777ed0

Please sign in to comment.