测试EF ConcurrencyCheck

时间:2013-01-03 14:36:08

标签: entity-framework unit-testing concurrency

我有一个基础对象,它包含一个Version属性,标记为ConcurrencyCheck

public class EntityBase : IEntity, IConcurrencyEnabled
{
    public int Id { get; set; }
    [ConcurrencyCheck] 
    [Timestamp]
    public byte[] Version { get; set; }
}

然而,这是有效的,我想编写测试以确保它不会被破坏。不幸的是,我似乎无法弄清楚如何编写一个不依赖于物理数据库的测试!

相关的测试代码有效,但使用数据库......

    protected override void Arrange()
    {
        const string asUser = "ConcurrencyTest1"; // used to anchor and lookup this test record in the db

        Context1 = new MyDbContext();
        Context2 = new MyDbContext();
        Repository1 = new Repository<FooBar>(Context1);
        Repository2 = new Repository<FooBar>(Context2);
        UnitOfWork1 = new UnitOfWork(Context1);
        UnitOfWork2 = new UnitOfWork(Context2);

        Sut = Repository1.Find(x => x.CreatedBy.Equals(asUser)).FirstOrDefault();

        if (Sut == null)
        {
            Sut = new FooBar
                {
                    Name = "Concurrency Test"
                };

            Repository1.Insert(Sut);
            UnitOfWork1.SaveChanges(asUser);
        }

        ItemId = Sut.Id;
    }

    protected override void Act()
    {
        _action = () =>
            {
                var item1 = Repository1.FindById(ItemId);
                var item2 = Repository2.FindById(ItemId);

                item1.Name = string.Format("Changed @ {0}", DateTime.Now);
                UnitOfWork1.SaveChanges("test1");

                item2.Name = string.Format("Conflicting Change @ {0}", DateTime.Now);
                UnitOfWork2.SaveChanges("test2"); //Should throw DbUpdateConcurrencyException
            };
    }

    [TestMethod]
    [ExpectedException(typeof(DbUpdateConcurrencyException))]
    public void Assert()
    {
        _action();
    }

如何删除数据库要求???

2 个答案:

答案 0 :(得分:0)

我建议将MyDbContext解压缩到接口IMyDbContext,然后创建一个TestDbContext类,它也会按照你的方式实现SaveChanges,除了返回一个随机值(如1)而不是实际保存到数据库。

那时你需要做的就是测试,事实上,所有实体的版本号都得到了提升。

或者您也可以执行示例found herehere

编辑:我实际上刚刚找到了使用TimeStamp进行this blog post并发检查的直接示例。

答案 1 :(得分:0)

我认为你不应该试图模仿这种行为来启用“纯”单元测试。有两个原因:

  • 它需要相当多的代码来模拟数据库行为:以具有版本值的方式实现对象,缓存原始对象(模拟存储),更新时修改版本值,比较版本值与原始版本值相同,在版本不同时抛出异常,可能更多。所有这些代码都可能受到错误的影响,更糟糕的是,可能与实际情况略有不同。

  • 你将陷入循环推理:你专门为单元测试编写代码然后......你编写单元测试来测试这段代码。绿色测试表明一切正常,但不包括应用程序代码的基本部分。

这只是linq对很难(不可能)模拟的实体的众多方面之一。我正在编制这些差异的清单here