C# 如何对使用实体框架的存储库模式进行单元测试?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15791303/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 17:58:35  来源:igfitidea点击:

How to unit test a repository pattern that uses Entity Framework?

c#entity-frameworkunit-testingrepository-pattern

提问by Randel Ramirez

I'm currently trying to unit test a repository I made through Entity Framework:

我目前正在尝试对我通过实体框架创建的存储库进行单元测试:

What I want to happen is that test the repository without actually sending/connecting to the actual database, I want to this without using any mocking framework.

我想要发生的是在不实际发送/连接到实际数据库的情况下测试存储库,我希望在不使用任何模拟框架的情况下进行。

Currently my test is sending the data to the database, what I want to happen is test the add/remove etc. methods without sending the actual data to the database since it's only for testing.

目前我的测试是将数据发送到数据库,我想要发生的是测试添加/删除等方法,而不将实际数据发送到数据库,因为它仅用于测试。

Here is the repository:

这是存储库:

namespace AbstractFactory.Repository
{
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;

    /// <summary>
    /// This class serves as the structure of the Author repository using a database
    /// </summary>
    public class DbAuthorRepository : IRepository<AuthorEntity>
    {

        private AbstractFactoryPatternEntities context;

        public DbAuthorRepository(AbstractFactoryPatternEntities context)
        {
            this.context = context;
        }

        /// <summary>
        /// Adds the specified author.
        /// </summary>
        /// <param name="author">The author.</param>
        public void Add(AuthorEntity author)
        {
            context.AuthorEntities.Add(author);
        }

        /// <summary>
        /// Removes the specified author.
        /// </summary>
        /// <param name="author">The author.</param>
        public void Remove(AuthorEntity author)
        {
            this.context.AuthorEntities.Remove(author);
        }

        /// <summary>
        /// Saves this instance.
        /// </summary>
        public void Save()
        {
            this.context.SaveChanges();
        }

        /// <summary>
        /// Gets all.
        /// </summary>
        /// <returns>returns a list of all the authors</returns>
        public IEnumerable<AuthorEntity> GetAll()
        {
            List<AuthorEntity> result = this.context.AuthorEntities.Include(a => a.Books).ToList();

            return result;
        }

        /// <summary>
        /// Gets the author by id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns>returns an entity</returns>
        public AuthorEntity GetById(int id)
        {
            AuthorEntity result = this.context.AuthorEntities.Single(a => a.AuthorId == id);

            return result;
        }
    }
}

Here is the current code for the unit test:

这是单元测试的当前代码:

[TestMethod]
        public void Add_MethodIsCalled_EntityCountIsIncrementedByOne()
        {
            using (ShimsContext.Create())
            {
                ShimAbstractFactoryPatternEntities context = new ShimAbstractFactoryPatternEntities(new AbstractFactoryPatternEntities());
                DbAuthorRepository repository = new DbAuthorRepository(context);
                repository.Add(new AuthorEntity { FirstName = "Test", LastName = "testing=" });
                var actual = repository.GetAll().Count();
                repository.Save();
                var expected = repository.GetAll().Count();
                Assert.AreNotEqual(actual, expected);
            }

            //AbstractFactoryPatternEntities context = new AbstractFactoryPatternEntities();
            //DbAuthorRepository repository = new DbAuthorRepository(context);
            //var actual = repository.GetAll().Count();
            //repository.Add(new AuthorEntity { FirstName = "Testing", LastName = "MyTest" });
            //repository.Save();
            //var expected = repository.GetAll().Count();
            //Assert.AreNotEqual(actual, expected);
        }

        [TestMethod]
        public void Remove_MethodIsCalled_EntityCountRemainsTheSame()
        {
            AbstractFactoryPatternEntities context = new AbstractFactoryPatternEntities();
            DbAuthorRepository repository = new DbAuthorRepository(context);
            AuthorEntity newAuthor = new AuthorEntity { FirstName = "Testing", LastName = "MyTest" };
            repository.Add(newAuthor);
            repository.Save();
            var actual = repository.GetAll().Count();
            Console.WriteLine(actual);
            repository.Remove(newAuthor);
            var expected = repository.GetAll().Count();
            Console.WriteLine(expected);
            Assert.AreEqual(actual, expected);
        }

        [TestMethod]
        public void Get_MethodIsCalled_CorrectAuthorIsRetrieved()
        {
            AbstractFactoryPatternEntities context = new AbstractFactoryPatternEntities();
            DbAuthorRepository repository = new DbAuthorRepository(context);
            int target = 4;
            AuthorEntity author = repository.GetById(target);
            Assert.AreEqual(target, author.AuthorId);
        }

I want to use shims/stub/fakes in order to make the test.

我想使用 shims/stub/fakes 来进行测试。

采纳答案by Wiktor Zychla

The Entity Framework repository is a concrete implementation of your repository interface. Because it is concrete, you can't abstract it and test without the database - the whole point of this concrete implementation is to write the data to the database!

实体框架存储库是存储库接口的具体实现。因为它是具体的,你不能在没有数据库的情况下对其进行抽象和测试——这个具体实现的重点是将数据写入数据库!

This means that testing EF repositories should rather aim at verifying that repositories write to actual database - in the act phase of your test you invoke repository methods and in the assert phase you use any other way of getting the data from the database (ado.net perhaps?) to check if the repository does its job.

这意味着测试 EF 存储库应该旨在验证存储库是否写入实际数据库 - 在测试的执行阶段调用存储库方法,在断言阶段使用任何其他方式从数据库中获取数据(ado.net也许?)来检查存储库是否完成了它的工作。

Yet another, unrelated thing is that you can have another implementation of the repository which uses an in-memory data store and injecting such in-memory repository to other services allows you to test these services wihout writing to a physical database. You could even mock a repository injected to other services just to perform some behavioral tests, i.e. test whether your services use your repositories correctly.

另一个不相关的事情是,您可以拥有另一个存储库实现,它使用内存数据存储并将此类内存存储库注入其他服务,允许您在不写入物理数据库的情况下测试这些服务。您甚至可以模拟一个注入其他服务的存储库,只是为了执行一些行为测试,即测试您的服务是否正确使用了您的存储库。

回答by druss

You can replace connection to your database with in-memory DB, such as Effort. Then you can test your repository logic. In more details can be found here

您可以使用内存数据库(例如 Effort)替换与数据库的连接。然后您可以测试您的存储库逻辑。可以在此处找到更多详细信息