本文介绍了单元测试DbContext的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

限时删除!!

我研究了一些有关可用于单元测试DbContext 的技术的信息.我想在上下文中添加一些内存数据,以便我的测试可以针对它进行.我正在使用数据库优先方法.

I've researched some information about techniques I could use to unit test a DbContext. I would like to add some in-memory data to the context so that my tests could run against it. I'm using Database-First approach.

我发现最有用的两篇文章是.这种方法依赖于创建MyContext和FakeContext都将实现的IContext接口,从而可以模拟上下文.

The two articles I've found most usefull were this and this.That approach relies on creating an IContext interface that both MyContext and FakeContext will implement, allowing to Mock the context.

但是,我试图避免使用存储库来提取EF,例如指出 有些人,因为EF 4.1已经通过DbSet和DbContext实现了存储库和工作单元模式,所以我真的很想保留EF团队实现的所有功能,而不必自己使用通用存储库来维护它们,例如我已经在其他项目中做了(这很痛苦).

However, I'm trying to avoid using repositories to abstract EF, as pointed by some people, since EF 4.1 already implements repository and unit of work patterns through DbSet and DbContext, and I really would like to preserve all the features implemented by the EF Team without having to maintain them myself with a generic repository, as I already did in other project (and it was kind of painful).

使用IContext将使我走同样的路(或者不是吗?).

Working with an IContext will lead me to the same path (or won't it?).

我考虑过创建一个继承自MyContext主要对象的FakeContext ,因此可以利用其下的DbContext来运行我的测试,而无需访问数据库.我找不到类似的实现,因此我希望有人可以对此提供帮助.

I thought about creating a FakeContext that inherits from main MyContext and thus take advantage of the DbContext underneath it to run my tests without hitting the database.I couldn't find similar implementations, so I'm hoping someone can help me on this.

我是在做错什么,还是可能导致我无法预料的一些问题?

推荐答案

问一个问题:您要测试什么?

Ask yourself a single question: What are you going to test?

您提到了FakeContext并模拟了上下文-为什么同时使用两者?那些只是做相同事情的不同方法-提供上下文的仅测试实现.

You mentioned FakeContext and Mocking the context - why to use both? Those are just different ways to do the same - provide test only implementation of the context.

还有一个更大的问题-伪造或模拟上下文或集合只有一个结果:您不再测试真实的代码.

There is one more bigger problem - faking or mocking context or set has only one result: You are not testing your real code any more.

简单的例子:

public interface IContext : IDisposable
{
     IDbSet<MyEntity> MyEntities { get; }
}

public class MyEntity
{
    public int Id { get; set; }
    public string Path { get; set; }
}

public class MyService
{
    private bool MyVerySpecialNetMethod(e)
    {
        return File.Exists(e.Path);
    }

    public IEnumerable<MyEntity> GetMyEntities()
    {
        using (IContext context = CreateContext())
        {
            return context.MyEntities
                          .Where(e => MyVerySpecialNetMethod(e))
                          .Select(e)
                          .ToList();
        }
    }
}

现在,假设您在SUT中拥有此功能(被测系统-在单元测试的情况下,它是一个单元=通常是一个方法).在测试代​​码中,您提供FakeContextFakeSet,它将起作用-您将获得绿色测试.现在,在生产代码中,您将提供另一个派生的DbContextDbSet,并且在运行时将获得异常.

Now imagine that you have this in your SUT (system under test - in case of unit test it is an unit = usually a method). In the test code you provide FakeContext and FakeSet and it will work - you will have a green test. Now in the production code you will provide a another derived DbContext and DbSet and you will get exception at runtime.

为什么?因为通过使用FakeContext,您还更改了LINQ提供程序,而不是将LINQ更改为Entities,而是运行LINQ to Objects,所以调用无法转换为SQL的本地.NET方法与LINQ中不可用的许多其他LINQ功能一样有效实体!您还可以通过数据修改找到其他问题-引用完整性,级联删除等.这就是为什么我认为处理上下文/LINQ to Entities的代码应该包含集成测试并针对实际数据库执行的原因.

Why? Because by using FakeContext you have also changed LINQ provider and instead of LINQ to Entities you are running LINQ to Objects so calling local .NET methods which cannot be converted to SQL works as well as many other LINQ features which are not available in LINQ to Entities! There are other issues you can find with data modification as well - referential integrity, cascade deletes, etc. That is the reason why I believe that code dealing with context / LINQ to Entities should be covered with integration tests and executed against the real database.

这篇关于单元测试DbContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

1403页,肝出来的..

09-07 01:42