EF Core 查询在真实数据库中运行良好,但测试失败

EF Core query working fine with real DB but the test fails

我正在使用 C#、.NET Core 2.2 和 Xunit 框架。

以下代码,方法 "GetTopFive",当我在 Web API 控制器中执行它并连接到真实数据库(SQL Server 2017)时工作正常。

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

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

    public IEnumerable<MovieRating> GetTopFive()
    {
        var result = _moviesDbContext.Movies.Include(x => x.Ratings)
                    .Select(x => new MovieRating
                    {
                        Id = x.Id,
                        Title = x.Title,
                        Average = x.Ratings.Average(y => y.RatingValue)
                    }).OrderByDescending(x => x.Average).ThenBy(x => x.Title).Take(5).ToList();

        return result;
    }
}

但是当我 运行 测试时我得到了这个错误:

Message: System.InvalidOperationException : Sequence contains no elements

这是测试代码,我用的是内存DB:

 public class MovieRepositoryTest : IClassFixture<MovieSeedDataFixture>
 {
    private readonly IMovieRepository _sut;
    private readonly MovieFilters _filters;

    public MovieRepositoryTest(MovieSeedDataFixture fixture)
    {
        _sut = new MovieRepository(fixture.MovieContext);
        _filters = new MovieFilters { Genre = "Action" };
    }

    [Fact]
    public void GetTopFiveMovies_WhenCalled_ReturnsFiveMovies()
    {
        //Act
        var movies = _sut.GetTopFive();

        //Assert
        Assert.Equal(5, movies.Count());
    }
 }

如果我通过删除 "OrderByDescending" 来更改存储库,它会起作用,但这不是我需要的结果:

public IEnumerable<MovieRating> GetTopFive()
{

        var result = _moviesDbContext.Movies.Include(x => x.Ratings)
            .Select(x => new MovieRating
            {
                Id = x.Id,
                Title = x.Title,
                Average = x.Ratings.Average(y => y.RatingValue)
            }).Take(5).ToList();

        return result;
}

这是夹具 class,显然有数据:

 public class MovieSeedDataFixture : IDisposable
{
    public MovieDbContext MovieContext { get; }

    public MovieSeedDataFixture()
    {
        var databaseName = "MovieListDatabase_" + DateTime.Now.ToFileTimeUtc();
        var options = new DbContextOptionsBuilder<MovieDbContext>()
            .UseInMemoryDatabase(databaseName)
            .Options;

        MovieContext = new MovieDbContext(options);

        // Load movies
        MovieContext.Movies.Add(new Movie { Id = 1, Title = "John Wick", YearOfRelease = 2015, Genre = "Action", RunningTime = 120 });
        MovieContext.Movies.Add(new Movie { Id = 2, Title = "John Wick: Chapter 2", YearOfRelease = 2017, Genre = "Action", RunningTime = 130 });
        MovieContext.Movies.Add(new Movie { Id = 3, Title = "Terminator 6", YearOfRelease = 2019, Genre = "Science Fiction/Action", RunningTime = 110 });
        MovieContext.Movies.Add(new Movie { Id = 4, Title = "The Saint", YearOfRelease = 2017, Genre = "Action", RunningTime = 120 });
        MovieContext.Movies.Add(new Movie { Id = 5, Title = "The Interview", YearOfRelease = 2014, Genre = "Action/Comedy", RunningTime = 120 });
        MovieContext.Movies.Add(new Movie { Id = 6, Title = "Mr. & Mrs. Smith", YearOfRelease = 2005, Genre = "Crime/Thriller", RunningTime = 115 });
        MovieContext.Movies.Add(new Movie { Id = 7, Title = "Fast & Furious 8", YearOfRelease = 2017, Genre = "Crime/Action", RunningTime = 125 });
        MovieContext.Movies.Add(new Movie { Id = 8, Title = "Fast & Furious 1", YearOfRelease = 2001, Genre = "Crime/Action", RunningTime = 120 });
        MovieContext.Movies.Add(new Movie { Id = 9, Title = "Jason Bourne", YearOfRelease = 2016, Genre = "Action", RunningTime = 135 });
        MovieContext.Movies.Add(new Movie { Id = 10, Title = "Iron Man 3", YearOfRelease = 2013, Genre = "Science Fiction/Action", RunningTime = 110 });

        // Load Users
        MovieContext.Users.Add(new User { Id = 1, FirstName = "John", Lastname = "Doe" });
        MovieContext.Users.Add(new User { Id = 2, FirstName = "Jane", Lastname = "Doe" });

        // Load Ratings
        MovieContext.Ratings.Add(new Rating { Id = 1, MovieId = 1, UserId = 1, RatingValue = 4 });
        MovieContext.Ratings.Add(new Rating { Id = 2, MovieId = 1, UserId = 2, RatingValue = 5 });
        MovieContext.Ratings.Add(new Rating { Id = 3, MovieId = 2, UserId = 1, RatingValue = 4 });
        MovieContext.Ratings.Add(new Rating { Id = 4, MovieId = 2, UserId = 2, RatingValue = 4 });
        MovieContext.Ratings.Add(new Rating { Id = 5, MovieId = 3, UserId = 1, RatingValue = 4 });
        MovieContext.Ratings.Add(new Rating { Id = 6, MovieId = 3, UserId = 2, RatingValue = 4 });
        MovieContext.Ratings.Add(new Rating { Id = 7, MovieId = 4, UserId = 1, RatingValue = 3 });
        MovieContext.Ratings.Add(new Rating { Id = 8, MovieId = 4, UserId = 2, RatingValue = 3 });
        MovieContext.Ratings.Add(new Rating { Id = 9, MovieId = 5, UserId = 1, RatingValue = 2 });
        MovieContext.Ratings.Add(new Rating { Id = 10, MovieId = 5, UserId = 2, RatingValue = 2 });
        MovieContext.Ratings.Add(new Rating { Id = 11, MovieId = 6, UserId = 1, RatingValue = 1 });
        MovieContext.Ratings.Add(new Rating { Id = 12, MovieId = 6, UserId = 2, RatingValue = 1 });

        MovieContext.SaveChanges();
    }

    public void Dispose()
    {
        MovieContext.Dispose();
    }
}

对我为什么会出现这个错误有什么帮助吗? 谢谢

问题与

有关
Average = x.Ratings.Average(y => y.RatingValue)

因为并非所有电影都有评级,Average() 将在空序列上抛出该异常。

如果你期待没有评级的电影,你可以使用三元表达式:

Average = x.Ratings.Any() ? x.Ratings.Average(y => y.RatingValue) : 0 // or null depending on your model