簡體   English   中英

使用 xUnit 動態測試所有 Entity Framework Core DbContext DbSet<> 對象

[英]Dynamically Test All Entity Framework Core DbContext DbSet<> objects with xUnit

我正在使用 xUnit 和 FluentAssertions 編寫集成測試來驗證我們的模型是否正確映射。 我們有幾十個 EF 上下文,對於每個上下文,都有一個或多個DbSet<>屬性,如下所示:

public class SomeContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder builder) { // ... }

    public virtual DbSet<User> Users { get; set; }
}

它們都以相同的方式布置,因此這將是使用[MemberData]動態獲取每個上下文作為測試和DbSet<>屬性的輸入,調用它,並確保它不會失敗的理想選擇一個簡單的查詢。 Container.GetInstance()調用是對我的 DI 容器的調用,以獲取實際的DbContext對象:

public class ContextTests
{
    public static IEnumerable<object[]> EntitiesMappedInCode =>
        typeof(DbContextInitializer).Assembly.GetTypes()
            .Where(t => t.IsSubclassOf(typeof(DbContext)) && !t.IsAbstract)
            .SelectMany(dbContextType =>
            {
                var context = (DbContext) Container.GetInstance(dbContextType);
                var entities = context.Model.GetEntityTypes();
                var dbSetProperties = context.GetType().GetProperties().Where(p =>
                    typeof(DbSet<>).IsAssignableFrom(p.PropertyType.GetGenericTypeDefinition()));
                
                return dbSetProperties.Select(dbSet => new [] {context, dbSet.GetValue(context)});
            });


    [Theory]
    [MemberData(nameof(EntitiesMappedInCode))]
    public void EntitiesDefinedInCode_ExistsInDatabase(DbContext context, object dbSetObject)
    {
        var dbSet = dbSetObject as DbSet<dynamic>; 
        dbSet.Invoking(dbSet => Queryable.FirstOrDefault<dynamic>(dbSet))
            .Should().NotThrow<SqlException>("the entity framework model should match the database");
    }
}

問題是反射無法正常工作以返回運行時實例,並且在p.PropertyType.GetGenericTypeDefinition()處失敗並出現錯誤。

有沒有人動態檢索上下文的DbSet<>屬性並成功調用它們的查詢?

拋出異常是因為GetGenericTypeDefinition()不適用於非泛型類型,因此您應該在調用它之前首先檢查類型是否實際上是泛型的:

var dbSetProps = typeof(HwContext).GetProperties().Where(c => 
        c.PropertyType.IsGenericType && 
        typeof(DbSet<>).IsAssignableFrom(c.PropertyType.GetGenericTypeDefinition()));

也不要DbSet<dynamic>DbSet<dynamic> ,只需使用dynamic

foreach (var prop in dbSetProps)
{
    dynamic dbSet = prop.GetValue(context);
    // this should not throw
    Queryable.FirstOrDefault(dbSet);                
}

感謝 Evk,我能夠讓它像這樣工作:

public class ContextTests
{
    public static IEnumerable<object[]> EntitiesMappedInCode =>
        typeof(DbContextInitializer).Assembly.GetTypes()
            .Where(t => t.IsSubclassOf(typeof(DbContext)) && !t.IsAbstract)
            .SelectMany(dbContextType =>
            {
                var dbSetProps = dbContextType.GetProperties()
                    .Where(c => c.PropertyType.IsGenericType 
                                && typeof(DbSet<>).IsAssignableFrom(c.PropertyType.GetGenericTypeDefinition()));
                var context = Container.GetInstance(dbContextType);
                return dbSetProps.Select(dbSetProp => new [] {context, dbSetProp.GetValue(context)});
            });


    [Theory]
    [MemberData(nameof(EntitiesMappedInCode))]
    public void EntitiesDefinedInCode_ExistsInDatabase(DbContext context, dynamic dbSet)
    {
        context.Invoking(dbContext => Queryable.FirstOrDefault(dbSet))
            .Should().NotThrow<SqlException>("the entity framework model should match the database");
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM