Запрос EF Core работает нормально с реальной БД, но тест не пройден - PullRequest
0 голосов
/ 21 января 2019

Я использую 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

Это тестовый код, который я использую в памяти БД:

 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;
}

И это класс прибора, который явно имеетданные:

 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();
    }
}

Любая помощь, почему я получаю эту ошибку?Спасибо

1 Ответ

0 голосов
/ 21 января 2019

Проблема связана с

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
...