如何使用 Moles 来查询 EntityFramework 4.1 中的数据库中的 DbContext?

发布于 2024-12-02 21:10:38 字数 782 浏览 0 评论 0 原文

我正在使用 Entity Framework 4.1 进行数据库访问,并希望对以下代码进行单元测试:

// Get all the entities including children
using (MyContext context = new MyContext())
{
    return context.EmployeeProfiles.Include("EmployeeProperties").ToList();
}

我正在使用 Moles 来消除数据库依赖项,但是我陷入了困境。我应该开始找出实体框架中的哪一点。

我正在关注这个 示例,但它适用于 LINQ-To-SQL。

我还考虑调试/跟踪实体框架,以找出在调用数据库之前拦截哪个函数。 但是,似乎没有可供 Entity Framework 4.1 跟踪的源代码。请参阅讨论

谁能指导我应该在 DbContext 中调出哪些函数,以便我可以获得 EmployeeProfiles 列表?

I am using Entity Framework 4.1 for database access and would like to Unit Test the following code:

// Get all the entities including children
using (MyContext context = new MyContext())
{
    return context.EmployeeProfiles.Include("EmployeeProperties").ToList();
}

I am using Moles to mole out the database dependency however I am stuck. Which point in the Entity Framework I should begin to mole out.

I was following this example but it is for LINQ-To-SQL.

I was also thinking of debugging/tracing the Entity Framework to figure out which function to intercept out before the call to the database is made.
However, it seems that there is no source code available for Entity Framework 4.1 to trace with. See discussion.

Can anyone guide me to which function(s) I should be moling out in the DbContext so I can get a list of EmployeeProfiles back?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

很酷不放纵 2024-12-09 21:10:38

在我看来,您不是通过存储库模式消除对 EF 的依赖,而是尝试模拟 EF 的特定行为。我看不出尝试这样做有什么意义,而且这会非常困难,EF 不应该被嘲笑。

您的存储库大概是这样的:

public interface IRepository
{
      IEnumerable<EmployeeProfiles> EmployeeProfiles { get; }
}

public class Repository
{
    public IEnumerable<EmployeeProfiles> EmployeeProfiles
    {
        get
        {
            // Get all the entities including children     
            using (MyContext context = new MyContext())     
            {
                return context.EmployeeProfiles.Include("EmployeeProperties").ToList();     
            }
        }
    }
}

这样您就删除了存储库对 EmployeeProfiles 如何返回的依赖。现在您可以模拟您的心意(尚未使用 Moles),但是使用 Moq,您可以执行以下操作:

public void TestEmptyList()
{
    var mock = new Mock<IRepository>();
    var expected = new List<EmployeeProfiles>();
    mock.SetupGet(ep => ep.EmployeeProfiles).Returns(expected);

    var actual = mock.Object.EmployeeProfiles;

    Assert.AreEqual(expected, actual);
}

因此,如果您将想要从数据库抽象的方法/属性放入存储库接口,然后您可以模拟出您想要测试它可能返回的任何值。

也许你无论如何都会这样做,我不确定。我不明白你为什么要对 EF 进行单元测试,你希望获得什么?这将是非常困难的,它不是为了被嘲笑而设计的(很少有接口/虚拟)。对您返回的数据的任何模拟(这实际上是您真正感兴趣的数据)都将按照上面的方式完成。

It looks to me like rather than removing the dependency on EF via a Repository pattern, you're trying to mock the specific behaviour of EF. I can't see the point in trying to do that and it would be very difficult, EF isn't meant to be mocked.

Your repository is presumably something like this:

public interface IRepository
{
      IEnumerable<EmployeeProfiles> EmployeeProfiles { get; }
}

public class Repository
{
    public IEnumerable<EmployeeProfiles> EmployeeProfiles
    {
        get
        {
            // Get all the entities including children     
            using (MyContext context = new MyContext())     
            {
                return context.EmployeeProfiles.Include("EmployeeProperties").ToList();     
            }
        }
    }
}

This way you have removed the repository dependency on how the EmployeeProfiles is returned. Now you can mock-away to your heart's content (haven't yet used Moles), but with Moq, you would do something like:

public void TestEmptyList()
{
    var mock = new Mock<IRepository>();
    var expected = new List<EmployeeProfiles>();
    mock.SetupGet(ep => ep.EmployeeProfiles).Returns(expected);

    var actual = mock.Object.EmployeeProfiles;

    Assert.AreEqual(expected, actual);
}

So, if you put the methods/properties you want to abstract away from the database into the repository interface, then you can mock out any values you want to test that it might return.

Maybe you're doing this anyway, I'm not sure. I don't see why you'd want to unit test EF, what would you hope to gain? It would be immensely hard, it's not designed to be mocked (very few interfaces/ virtuals). Any mocking of data you return, which is really all you are really interesting in would be done as above.

洒一地阳光 2024-12-09 21:10:38

这是完全可能的,而且在我看来,是有效的。是的,您可以使用存储库模式并模拟您的存储库,通常这就足够了。

然而,我见过两个关于模拟 EF 的论点:

  1. EF 已经是实际数据库的抽象/存储库,没有必要围绕它编写另一个存储库。
  2. 您通过 EF 编写的任何存储库都是您的代码。因此,您应该对其进行测试,因为迟早您最终会添加需要覆盖的逻辑。

目前这有点像一场圣战,但有一些论据支持你正在做的事情。

因此,要对 Moles 执行此操作,您需要做两件事。首先,更改创建 DbContext 的模板,以便所有表的返回类型均为 IDbSet 而不是 DbSet

然后,在您的测试项目中,添加 IDbSet 的测试类实现。我发现这个效果很好。

现在,在测试中,您可以执行以下操作:

List<EmployeeProfile> testProfiles = /*your test data here*/;
MMyContext.AllInstances.EmployeeProfilesGet  = (instance) => 
{
    return new InMemoryDbSet<EmployeeProfile>(testProfiles);
};


// Get all the entities including children
using (MyContext context = new MyContext())
{
    return context.EmployeeProfiles.Include("EmployeeProperties").ToList();
}

它快速、简单,并且允许您测试代码,直到它脱离您的控制。

This is totally possible, and in my opinion, valid. Yes, you can use a repository pattern and mock your repository, and often that is good enough.

However, two arguments I've seen for mocking EF:

  1. EF is already an abstraction/repository over the actual database, writing another repository around it isn't necessary.
  2. Any repository you write over EF is your code. Therefore, you should test it, as sooner or later you're going to end up adding logic that needs to be covered.

This is a bit of a holy war at this point, but there are arguments out there that support what you are doing.

So, to do this with Moles, you'll need to do two things. First, change the template that creates your DbContext so that the return types of all your tables are IDbSet<> instead of DbSet<>.

Then, in your test project, add a test class implementation for IDbSet. I've found this one to work well.

Now, in your test, you can do the following:

List<EmployeeProfile> testProfiles = /*your test data here*/;
MMyContext.AllInstances.EmployeeProfilesGet  = (instance) => 
{
    return new InMemoryDbSet<EmployeeProfile>(testProfiles);
};


// Get all the entities including children
using (MyContext context = new MyContext())
{
    return context.EmployeeProfiles.Include("EmployeeProperties").ToList();
}

It's quick, simple, and allows you to test your code right up to the very point it leaves your control.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文