猿问

模拟 EF 核心 dbcontext 和 dbset

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


消息:System.NotSupportedException:非虚拟(在 VB 中可覆盖)成员上的设置无效: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;

    }

  }

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


public class MovieDbContext: DbContext

{

    public MovieDbContext(DbContextOptions<MovieDbContext> options) : base(options)

    {


    }


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

}

慕尼黑5688855
浏览 97回答 3
3回答

万千封印

我看到您DbContext在MovieRepository. 因此,不使用模拟,使用 EF CoreInMemory数据库将是您的绝佳选择。这也将降低复杂性。编写您的GetAllTest()方法如下:[Fact]public void GetAllTest(){&nbsp; &nbsp; &nbsp; &nbsp; var options = new DbContextOptionsBuilder<MovieDbContext>()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .UseInMemoryDatabase(databaseName: "MovieListDatabase")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .Options;&nbsp; &nbsp; &nbsp; &nbsp; // Insert seed data into the database using one instance of the context&nbsp; &nbsp; &nbsp; &nbsp; using (var context = new MovieDbContext(options))&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; context.Movies.Add(new Movie {Id = 1, Title = "Movie 1", YearOfRelease = 2018, Genre = "Action"});&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; context.Movies.Add(new Movie {Id = 2, Title = "Movie 2", YearOfRelease = 2018, Genre = "Action"});&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; context.Movies.Add(new Movie {Id = 3, Title = "Movie 3", YearOfRelease = 2019, Genre = "Action"});&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; context.SaveChanges();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; // Use a clean instance of the context to run the test&nbsp; &nbsp; &nbsp; &nbsp; using (var context = new MovieDbContext(options))&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MovieRepository movieRepository = new MovieRepository(context);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; List<Movies> movies == movieRepository.GetAll();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Assert.Equal(3, movies.Count);&nbsp; &nbsp; &nbsp; &nbsp; }}注意:不要忘记安装Microsoft.EntityFrameworkCore.InMemorynuget包如下:安装包 Microsoft.EntityFrameworkCore.InMemory

尚方宝剑之说

为了节省您的时间,请尝试使用我的 Moq/NSubstitute 扩展 MockQueryable:https ://github.com/romantitov/MockQueryable 支持所有同步/异步操作//1 - create a List<T> with test itemsvar users = new List<UserEntity>(){&nbsp;new UserEntity,&nbsp;...};//2 - build mock by extensionvar mock = users.AsQueryable().BuildMock();//3 - setup the mock as Queryable for Moq_userRepository.Setup(x => x.GetQueryable()).Returns(mock.Object);//3 - setup the mock as Queryable for NSubstitute_userRepository.GetQueryable().Returns(mock);也支持 DbSet//2 - build mock by extensionvar mock = users.AsQueryable().BuildMockDbSet();//3 - setup DbSet for Moqvar userRepository = new TestDbSetRepository(mock.Object);//3 - setup DbSet for NSubstitutevar userRepository = new TestDbSetRepository(mock);笔记:从 1.0.4 版本开始支持 AutoMapper从 1.1.0 版本开始支持 DbQuery从 3.0.0 版本开始支持 EF Core 3.0

FFIVE

使用Moq.EntityFrameworkCore包。这很简单:var myDbContextMock = new Mock<MyDbContext>();IList<Entity> entities = new List<Entity>() { new Entity(), new Entity() };myDbContextMock.Setup(x => x.Entities).ReturnsDbSet(entities);
随时随地看视频慕课网APP
我要回答