模拟 EF 核心 dbcontext 和 dbset [英] Mocking EF core dbcontext and dbset

查看:32
本文介绍了模拟 EF 核心 dbcontext 和 dbset的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是 ASP.NET Core 2.2、EF Core 和 MOQ.当我运行测试时,我收到此错误:

I am using ASP.NET Core 2.2, EF Core and MOQ. When I run the test I am getting this error:

消息:System.NotSupportedException:非虚拟(在 VB 中可覆盖)成员上的设置无效:x => x.Movies

Message: System.NotSupportedException : Invalid setup on a non-virtual (overridable in VB) member: x => x.Movies

我做错了什么?

public class MovieRepositoryTest
{
    private readonly MovieRepository _sut;

    public MovieRepositoryTest()
    {
        var moviesMock = CreateDbSetMock(GetFakeListOfMovies());
        var mockDbContext = new Mock<MovieDbContext>();
        mockDbContext.Setup(x => x.Movies).Returns(moviesMock.Object);
        _sut = new MovieRepository(mockDbContext.Object);
    }

    [Fact]
    public void GetAll_WhenCalled_ReturnsAllItems()
    {
        //Act
        var items = _sut.GetAll();

        //Assert
        Assert.Equal(3, items.Count());
    }

    private IEnumerable<Movie> GetFakeListOfMovies()
    {
        var movies = new List<Movie>
        {
            new Movie {Id = 1, Title = "Movie 1", YearOfRelease = 2018, Genre = "Action"},
            new Movie {Id = 2, Title = "Movie 2", YearOfRelease = 2018, Genre = "Action"},
            new Movie {Id = 3, Title = "Movie 3", YearOfRelease = 2019, Genre = "Action"}
        };

        return movies;
    }

    private static Mock<DbSet<T>> CreateDbSetMock<T>(IEnumerable<T> elements) where T : class
    {
        var elementsAsQueryable = elements.AsQueryable();
        var dbSetMock = new Mock<DbSet<T>>();

        dbSetMock.As<IQueryable<T>>().Setup(m => m.Provider).Returns(elementsAsQueryable.Provider);
        dbSetMock.As<IQueryable<T>>().Setup(m => m.Expression).Returns(elementsAsQueryable.Expression);
        dbSetMock.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(elementsAsQueryable.ElementType);
        dbSetMock.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(elementsAsQueryable.GetEnumerator());

        return dbSetMock;
    }
  }

这是我的数据库上下文,带有 Movie dbSet:

And this is my DB Context, with the Movie dbSet:

public class MovieDbContext: DbContext
{
    public MovieDbContext(DbContextOptions<MovieDbContext> options) : base(options)
    {

    }

    public DbSet<Movie> Movies { get; set; }
}

以及带有要测试的方法 GetAll 的 Repository:

And the Repository with the method GetAll to be tested:

 public class MovieRepository: IMovieRepository
{
    private readonly MovieDbContext _moviesDbContext;
    public MovieRepository(MovieDbContext moviesDbContext)
    {
        _moviesDbContext = moviesDbContext;
    }

    public IEnumerable<Movie> GetAll()
    {
        return _moviesDbContext.Movies;
    }
}

推荐答案

我看到您在 MovieRepository 中使用了 EF 核心 DbContext.因此,与使用模拟不同,使用 EF Core InMemory 数据库对您来说将是一个不错的选择.这也将降低复杂性.

I see you are using EF core DbContext in your MovieRepository. So instead of using mock, Using EF Core InMemory database will be a great option for you. This will also reduce the complexity.

编写您的 GetAllTest() 方法如下:

Write your GetAllTest() method as follows:

[Fact]
public void GetAllTest()
{
        var options = new DbContextOptionsBuilder<MovieDbContext>()
            .UseInMemoryDatabase(databaseName: "MovieListDatabase")
            .Options;

        // Insert seed data into the database using one instance of the context
        using (var context = new MovieDbContext(options))
        {
            context.Movies.Add(new Movie {Id = 1, Title = "Movie 1", YearOfRelease = 2018, Genre = "Action"});
            context.Movies.Add(new Movie {Id = 2, Title = "Movie 2", YearOfRelease = 2018, Genre = "Action"});
            context.Movies.Add(nnew Movie {Id = 3, Title = "Movie 3", YearOfRelease = 2019, Genre = "Action"});
            context.SaveChanges();
        }

        // Use a clean instance of the context to run the test
        using (var context = new MovieDbContext(options))
        {
            MovieRepository movieRepository = new MovieRepository(context);
            List<Movies> movies == movieRepository.GetAll()

            Assert.Equal(3, movies.Count);
        }
}

注意:不要忘记安装 Microsoft.EntityFrameworkCore.InMemory nuget 包如下:

Note: Don't forget to install Microsoft.EntityFrameworkCore.InMemory nuget package as follows:

安装包 Microsoft.EntityFrameworkCore.InMemory

Install-Package Microsoft.EntityFrameworkCore.InMemory

有关更多详细信息:使用 InMemory 进行测试

这篇关于模拟 EF 核心 dbcontext 和 dbset的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆