简体   繁体   English

努力支持的单元测试冲突

[英]Effort supported unit tests conflict

I've inherited some tests with this project. 我已经对该项目继承了一些测试。 They were working when running against the SQL database, but slowly. 在针对SQL数据库运行时,它们正在工作,但速度很慢。 I'm trying to switch over to using Effort. 我正在尝试改用Effort。
.NET4.5, EF6.2, Effort 1.3.10. .NET4.5,EF6.2,努力1.3.10。

I have two possibly related issues with my unit tests. 我的单元测试有两个可能相关的问题。

It doesn't matter if I run the tests in parallel or not. 是否并行运行测试都没有关系。

1) If I run more than one at a time, I get 1)如果我一次跑多个,我得到

Saving or accepting changes failed because more than one entity of type 'Center.Shared.Person' have the same primary key value. 保存或接受更改失败,因为多个“ Center.Shared.Person”类型的实体具有相同的主键值。 Ensure that explicitly set primary key values are unique. 确保显式设置的主键值是唯一的。 Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. 确保在数据库和实体框架模型中正确配置了数据库生成的主键。 Use the Entity Designer for Database First/Model First configuration. 将实体设计器用于数据库优先/模型优先配置。 Use the 'HasDatabaseGeneratedOption" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration. ---> System.InvalidOperationException: Saving or accepting changes failed because more than one entity of type 'Center.Shared.Person' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration.. 使用“ HasDatabaseGeneratedOption”流利的API或“ DatabaseGeneratedAttribute”进行代码优先配置---> System.InvalidOperationException:由于多个“ Center.Shared.Person”类型的实体具有相同的主键值,因此保存或接受更改失败。确保显式设置的主键值是唯一的;确保在数据库和Entity Framework模型中正确配置了数据库生成的主键;使用“实体设计器”进行数据库优先/模型优先配置;使用“ HasDatabaseGeneratedOption”流利API或代码优先配置的“ DatabaseGeneratedAttribute”。

So it appears that the tests are not properly isolated. 因此,似乎没有正确隔离测试。
Tracing through the code, I can see that CreateTransient is called, but it apparently isn't transient enough. 跟踪代码,我可以看到调用了CreateTransient,但是显然它不够短暂。

    public DbConnection CreateConnection(string nameOrConnectionString)
    {
        lock (_lock)
        {
            if (_connection == null)
            {
                _connection = Effort.DbConnectionFactory.CreateTransient();
            }

            return _connection;
        }
    }

In the TestInitialize routine I try to reset the database. 在TestInitialize例程中,我尝试重置数据库。

    [TestInitialize]
    public override void Initialize()
    {
        db.Database.Delete();
        db.Database.CreateIfNotExists();
        db.Database.Initialize(true);

This is highly convoluted code, so if we need to post more code, it's a long time before we get to the bottom of the rabbit hole. 这是一个高度复杂的代码,因此,如果我们需要发布更多代码,则需要很长时间才能深入研究。 Probably better to create a PoC. 创建PoC可能更好。

2) If I run the tests independently, I get a different problem. 2)如果我独立运行测试,则会遇到其他问题。 Again, these passed against SQL but not Effort. 再次,这些通过了SQL,但没有通过。

    [TestMethod]
    public void ClientAccessorTests_Find()
    {
        Client result;
        Client client = new Client()
        {
            Complete = false,
            HeadOfHousehold = true,
            PersonID = _person.PersonID
        };

        _accessor.Create(client, _accessor.DefaultConnectionContext);

        result = _accessor.Find(new object[] { client.ClientID }, _accessor.DefaultConnectionContext);

        Assert.IsNotNull(result);  // Fails with Assert.IsNotNull failed. 
    }

Create consists of 创建包括

    public virtual EntityType Create(EntityType entity, ConnectionContext connectionContext)
    {
        IsContextValid(connectionContext);
        if (entity == null) throw new ArgumentException("", "entity");

        using (var db = CreateDbContext<DbContextType>(connectionContext))
        {
            db.Set<EntityType>().Add(entity);
            db.SaveChanges();
        }

        return entity;
    }

Find consists of 查找包括

    public virtual EntityType Find(object[] primaryKey, ConnectionContext connectionContext)
    {
        IsContextValid(connectionContext);
        if (primaryKey == null || primaryKey.Length == 0) throw new ArgumentException("", "primaryKey");

        using (var db = CreateDbContext<DbContextType>(connectionContext))
        {
            return db.Set<EntityType>().Find(primaryKey);
        }
    }

I know it is calling CreateDbContext, but tracing into the code, as far as I can tell it appears to be the same database with the same ID. 我知道它正在调用CreateDbContext,但是据我所知,它看起来像是具有相同ID的相同数据库。

What is it that should cause the tests to be isolated? 是什么导致测试隔离?
And any ideas on why Find would quit working when using an in-memory database? 关于使用内存数据库时查找为什么会退出工作的任何想法?

I was trying to use the implicit approach, where everything is hooked up via settings in the app.config file. 我试图使用隐式方法,其中所有内容都通过app.config文件中的设置进行连接。
I started having better luck once I abandoned that approach and created the database connection and set it explicitly. 一旦我放弃了这种方法并创建了数据库连接并进行了显式设置,我就开始有了好运。

        System.Data.Common.DbConnection connection = new EffortProviderFactory("").CreateConnection("");
        _accessor = new ClientAccessor();
        _accessor.Connection = connection;
        db = new EntitiesDb(connection);

The base Accessor creates copies of the DB at every turn, which is fine so long as it uses the same DbConnection. 基本访问器会随时创建数据库的副本,这很好,只要它使用相同的DbConnection。 So I set that on the accessor and then use it here: 所以我在访问器上设置了它,然后在这里使用它:

        if (_connection == null) {   // this is the path for the application
            if (connectionContext == null) {
                ret = new T();
            } else {
                ret = (T)Activator.CreateInstance(typeof(T), new object[] { connectionContext });
            }
        } else {  // this is the path for unit tests.
            ret = (T)Activator.CreateInstance(typeof(T), new object[] { _connection });
        }

Finally, I had to add a constructor that took a DbConnection to DbContext and its decendants. 最后,我必须添加一个将DbConnection带入DbContext及其后代的构造函数。

    public EntitiesDb(DbConnection connection) : base(connection) { }

'Find' now works and the tests don't interfere with each other. “查找”现在可以正常工作,并且测试不会相互干扰。
Next step is pushing this all down to the base classes. 下一步是将所有这些推入基类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM