运行 一次所有测试都会导致其中一些测试失败,但是当它们被单独触发时,它们就可以正常工作

Running all tests at once result in some of them failing, but when they're being fired alone, then they work fine

我有一些奇怪的问题,每当我 Run all 测试时,我的一些测试都会失败,但是当我一个接一个地启动它们时,一切正常

这是播种失败的代码 InMemoryDatabase

它必须添加一些 PermissionPermissions table 然后创建 Group 与权限

有多对多关系

基本上一个组可以有多个权限,一个权限可以在多个组中使用

但问题是

.Single 抛出

Sequence contains more than one element

当所有测试同时 运行 时,但单独 运行 时一切正常

有什么想法吗?

public class Tests : IDisposable
{
    private readonly Context _context;

    public void Dispose()
    {
        _context.Database.EnsureDeleted();
    }

    public Tests()
    {
        var o = new DbContextOptionsBuilder<Context>();
        o.UseInMemoryDatabase("testDb");
        _context = new Context(o.Options);
        _context.Database.EnsureDeleted();
        _context.Database.EnsureCreated();
    }

    [Fact]

    public async void myTest()
    {
        Initializer.InitializePermissions(_context);
        Initializer.InitializeGroups(_context);
        (...)
    }
}

public static class Initializer
{
    public static void InitializePermissions(Context context)
    {
        var permissionNames = new List<string>
        {
            "CanCreateNewProduct",
            "CanRemoveProduct",
        };

        foreach (var permission in permissionNames)
        {
            context.Permissions.Add(new Permission(permission));
        }

        context.SaveChanges();
    }   

    public static void InitializeGroups(Context context)
    {
        var groups = new Dictionary<string, List<string>>();

        groups.add("Admin", new List<string>{"CanRemoveProduct"};

        foreach (var group in groups)
        {
            foreach (var permissionName in group.Value)
            {
                var permission = context.Permissions.Single(x => x.Name == permissionName);

                group.GroupPermissions.Add
                (
                    new Many2Many
                    {
                        Group = group,
                        GroupId = group.Id,
                        Permission = permission,
                        PermissionId = permission.Id
                    }
                );
            }

            context.Groups.Add(new Group(group.Key, permissions);
        }

        context.SaveChanges();
    }
}

这里的问题是您的测试正在使用共享状态。

(顺便说一句,如果你想知道为什么很多程序员会竭尽全力避免使用任何东西 static 并且你觉得他们的对象,依赖注入等在他们可以使用的时候过于复杂只是 "make it static"... 这就是原因。)

你的Initializer可以可能保持static,只要它不在内部保持状态。至少乍一看似乎不是,因为您将数据库上下文的实例传递给它。但是当你继续在你的系统中工作时,重要的是要保持这个初始化器在测试中不保持任何状态。

这将我们带到 in-memory 数据库本身:

o.UseInMemoryDatabase("testDb");

这些可在整个应用程序中全局访问。 但是您可以为它们指定唯一的名称。例如:

var dbName = Guid.NewGuid().ToString();
o.UseInMemoryDatabase(dbName);

有了这个,每个数据库上下文都应该有一个唯一的数据库,您以后可以在任何需要的地方使用 dbName 引用它。因此,即使所有数据库在技术上都是全球可用的,任何给定的测试都只知道它自己的并且只能引用它自己的。

(当然要注意性能。如果您发现自己创建了大型复杂的数据库,而对于小型的个人测试则不应该这样做,然后创建 many 这些数据库一次可能会减慢速度。)