Должны ли модульные тесты знать о NHibernate? - PullRequest
0 голосов
/ 29 августа 2010

Я слежу за предыдущим вопросом . Ответ, который я принял, включает использование универсального IRepository для обработки базового CRUD, обернутого специфичным для домена IMovieRepository, который делегирует универсальной установке. Дальнейшие подробности включают использование метода WrapQueryInSession для универсального IRepository:

IEnumerable<T> WrapQueryInSession(Func<ISession, IEnumerable<T>> query);

Я приступил к реализации, когда понял, что это предоставляет NHibernate ISession потребителям универсального репозитория. В противном случае NHibernate полностью содержится в реализации IRepository, но для сигнатуры этого метода.

Это выходит на первый план, когда я хочу провести модульный тест MovieRepository, имея IRepository, реализованный в RepositoryFake, переданный конструктору MovieRepository:

protected override void BeforeEachTest()
{
    _fixture = new MovieRepository(new RepositoryFake());
}

Мой тестовый класс имеет частную реализацию поддельного репозитория:

private class RepositoryFake : IRepository<Movie>
{
    ...
    public IEnumerable<Movie> WrapQueryInSession(Func<ISession, IEnumerable<Movie>> query)
    {
        ...
    }
    ...
}

Способ настройки, тестовый класс и любой другой потребитель реализации IRepository узнают о ISession из NHibernate и, следовательно, о самом NHibernate. Это похоже на утечку абстракции.

Есть ли лучший способ полностью ограничить использование NHibernate в реализации IRepository?

Ответы [ 2 ]

2 голосов
/ 30 августа 2010

Я согласен с принципом, согласно которому NHibernate не следует абстрагировать полностью, но я обнаружил, что интерфейс запросов NHibernate можно скрыть без особых хлопот и это может произойти с помощью объектов Query.

Каждый объект запроса должен использовать возможности, предоставляемые NHibernate (ISession, ICriteria, IQuery и т. Д.), И может быть выполнен реализацией IRepository.

Наличие объектов Query вместо методов в ваших репозиториях обеспечивает лучшую тестируемость и не требует никаких ссылок на NHibernate в ваших тестовых классах.

Вот как все это может выглядеть:

public interface IRepository
{
        ISession Session { get; }
        TResult Query<TResult>(IQuery<TResult> query);
}

public class Repository : IRepository
{
    public ISession Session
    {
        get { return /* Call the session factory to return an ISession */; }
    }

    public TResult Query<TResult>(IQuery<TResult> query)
    {
        return query.Execute(Session));
    }
}

public interface IQuery<TResult>
{
    TResult Execute(QueryContext context);
}

public abstract class Query<TResult> : IQuery<TResult>
{
    public abstract TResult Execute(ISession session);
}

public class GetPeopleByName: IQuery<Person>
{
    private readonly string _name;

    public GetPeopleByName(string name)
    {
        _name = name;
    }

    public override IList<Person> Execute(ISeesion session)
    {
        var query = context.Session.CreateCriteria(typeof(Person))
            .Add(Restrictions.Eq("Name", _name));

        return query.List<Person>();
    }
}

Тогда вы можете использовать выше, как:

IRepository repository = /* Get somehow the implementation */
IList<Person> people = repository.Execute(new GetPeopleByName("Anna"));
2 голосов
/ 29 августа 2010

Идея моего ответа на ваш предыдущий вопрос состояла в том, что универсальный IRepository известен только внутри вашего уровня инфраструктуры - он не публикуется за пределами этого. Когда вы публикуете ISession в неуниверсальных репозиториях, они получают очень универсальный интерфейс, поскольку у них есть доступ к ISession для запросов. Проблема, связанная с отсутствием доступа к ISession, заключается в том, что ваш общий репозиторий будет:

  1. Ограничьте свои возможности запросов или
  2. Имейте целый ряд различных методов для запросов (в основном, дублируя интерфейс ISession.

Кажется, что это пустая трата, в которой интерфейс запросов NHibernate скрыт внутри фасада (которым будет ограничен общий репозиторий).

IMO, если вы выберете nHibernate, вы должны использовать всю мощь, которую он вам дает, и жить с зависимостью на протяжении всей вашей dll инфраструктуры (включая тесты). Думайте об общем интерфейсе IRepository как о вспомогательном интерфейсе с NHibernate, чтобы уменьшить количество дублирующегося кода внутри репозиториев.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...