using System.Linq.Expressions; using MicCheck.Api.Data; using Microsoft.EntityFrameworkCore; using Moq; namespace MicCheck.Api.Tests.Unit.TestSupport; public static class MockDbSetFactory { public static Mock> Create(List data) where T : class { var queryable = data.AsQueryable(); var mockSet = new Mock>(); mockSet.As>() .Setup(m => m.GetAsyncEnumerator(It.IsAny())) .Returns(() => new TestAsyncEnumerator(data.GetEnumerator())); mockSet.As>().Setup(m => m.Provider).Returns(() => new TestAsyncQueryProvider(data.AsQueryable().Provider)); mockSet.As>().Setup(m => m.Expression).Returns(() => data.AsQueryable().Expression); mockSet.As>().Setup(m => m.ElementType).Returns(queryable.ElementType); mockSet.As>().Setup(m => m.GetEnumerator()).Returns(() => data.GetEnumerator()); mockSet.Setup(m => m.Add(It.IsAny())).Callback(item => data.Add(item)); mockSet.Setup(m => m.AddRange(It.IsAny>())).Callback>(items => data.AddRange(items)); mockSet.Setup(m => m.Remove(It.IsAny())).Callback(item => data.Remove(item)); mockSet.Setup(m => m.RemoveRange(It.IsAny>())).Callback>(items => { foreach (var item in items.ToList()) data.Remove(item); }); return mockSet; } public static void SetupDbSet(this Mock context, Expression>> selector, List data) where T : class => context.Setup(selector).Returns(Create(data).Object); /// /// Sets up a DbSet whose Add() simulates database-generated identity assignment (needed because /// Moq does not run SaveChanges and entity Id properties are commonly init-only). /// public static void SetupDbSetWithGeneratedIds(this Mock context, Expression>> selector, List data) where T : class { var idProperty = typeof(T).GetProperty("Id") ?? throw new InvalidOperationException($"{typeof(T).Name} has no Id property."); var mockSet = Create(data); mockSet.Setup(m => m.Add(It.IsAny())).Callback(item => { idProperty.SetValue(item, data.Count + 1); data.Add(item); }); context.Setup(selector).Returns(mockSet.Object); } }