Модульное тестирование двухстороннего отношения EF

Я делаю небольшой практический проект, чтобы улучшить свои навыки модульного тестирования. Сначала я использую код Entity Framework.

Я использую FakeDBSet, который хорошо работает для простых списков сущностей. Когда деревья сущностей возвращаются, все не так хорошо. В частности, двухсторонние отношения не поддерживаются, поскольку это часть магии Entity Framework.

У меня есть два класса:

public class Book
{
    public virtual ICollection<Review> Reviews {get; set;}
}

public class Review
{
    public virtual Book Book { get; set;}
}

Если я установлю книгу для обзора, обзор не будет добавлен в сборник рецензий на книгу. Это происходит при использовании EF, но не в моей поддельной версии.

есть ли способ издеваться над этим поведением, или я не должен полагаться на EF для реализации двухсторонних отношений? Или издевательство над контекстом данных-пустая трата времени?

2 ответов


Это на самом деле довольно распространенная проблема (и один не очень хороший ответ). Существует процесс, который происходит внутри EF под названием fixups, который работает внутри цикла обнаружения изменений (тот, который запускает add/remove и несколько других изменений). Это оценивает обратные ссылки в вашей модели. Когда вы начнете издеваться над своим контекстом, вы потеряете цикл обнаружения изменений и, следовательно, исправления.

в прошлом я обошел это, понимая это конкретное ограничение из моих насмешек и убедившись, что я делаю свой код установки правильно, чтобы иметь смысл в коде (что позволяет столкнуться с ним довольно неидеально). Другой вариант - перейти к какой-то форме реальной облегченной базы данных в модульных тестах и продолжать использовать EF.


возможное решение, которое я нашел, - создать макет объекта, который имитирует код исправления EF.

вот пример использования насмешливой структуры NSubstitute:

private static Book CreateMockBook()
{
    var book = Substitute.For<Book>();

    // Mock EF fixup: Add a review to collection should also set book for the review
    book.Reviews.Add(Arg.Do<Review>((x) => { if(x.Book != book) x.Book = book; }));

    return book;
}

private static Review CreateMockReview()
{
    var review = Substitute.For<Review>();

    // Mock EF fixup: Set a book for the review should also should add the review to book's review collection
    review.When(x  => x.Book = Arg.Any<Book>()).Do(x => review.Book.Review.Add(review));

    return review;
}

это работает довольно хорошо, но я не уверен, что необходимость издеваться над этим поведением является признаком того, что мои тесты стали слишком сложными или что мой код использует побочные эффекты, которые он не должен.

мне было бы интересно, что другие люди думают об этом?