Как вы тестируете DAL? - PullRequest
3 голосов
/ 13 апреля 2011

В моем приложении есть Уровень доступа к данным, который оборачивает провайдер данных ADO.NET. DAL преобразует данные, возвращаемые поставщиком данных, в объекты .NET. Я видел много постов, в которых рекомендовалось не тестировать модуль DAL, но меня беспокоит, что так много может пойти не так - там много циклов, приведений и нулевых проверок.

У меня были некоторые мысли о создании фиктивного DbProvider с чем-то вроде RhinoMocks, но количество интерфейсов, которые я должен был бы макетировать в каждом тесте, было бы ошеломляющим, и количество ожиданий, которые я должен был бы установить, сделало бы тесты очень трудно читать. Кажется, что каждый тест был бы более сложным, чем код, который он тестировал - что было бы катастрофой с точки зрения 3 целей модульного тестирования:

  1. читаемость
  2. ремонтопригодность
  3. Достоверность

У меня была идея реализовать дружественный DbProviderFactory для загрузки образцов данных из xml. Я мог подключить его через Dependency Injection в тестах. Это должно значительно упростить ведение тестов. Тривиальный пример может быть:

[TestCase]
public void CanGetCustomer()
{
    var expectedCommand = new XmlCommand("sp_get_customer");
    expectedCommand.ExpectExecuteDataReader(
        resultSet: @"<customer firstName=""Joe"" lastName=""Blogs"" ... />");

    var factory = new XmlProviderFactory(expectedCommand);

    var dal = new CustomerDal(factory);
    Customer customer = dal.GetCustomer();

    Assert.IsNotNull(customer, "The customer should never be null");
    Assert.AreEqual(
        "Joe", customer.FirstName, 
        "The customer had an unexpected FirstName.");
}

Я думаю, что этот подход - использование дружественного DbProvider - может упростить тестирование кода DAL. Это будет иметь следующие преимущества:

  1. Тестовые данные будут в формате xml и могут быть помещены в систему контроля версий вместе с модульными тестами. Это может быть во внешних файлах или в строках в тестах.
  2. Я не использую реальную базу данных, поэтому это устраняет проблему с состоянием. Поэтому мне не нужно переводить базу данных в известное состояние перед каждым тестом.
  3. Мне не нужно макетировать все интерфейсы ADO.NET в каждом тесте. Я напишу один набор фальшивых реализаций, которые я смогу повторно использовать по всей базе кода.

Могут ли люди дать некоторую критику по этой идее? Уже есть подобная реализация, которую я мог бы использовать для этого?

Спасибо

1 Ответ

2 голосов
/ 21 мая 2011

Я сталкиваюсь с множеством философских рассуждений на тему правильного модульного тестирования (нет, не интеграционного тестирования) классов доступа к данным (DAL, DAC, DAO, репозитории и т. Д.). Некоторые утверждают, что это бессмысленно, поскольку вы проводите интеграционное тестирование. Я нахожу огромное значение в модульном тестировании этих часто игнорируемых блоков кода. Во-первых, для правильного модульного тестирования класса доступа к данным он должен быть правильно структурирован и должен рисовать линии в песке, с которыми могут взаимодействовать потребители - думать, интерфейсы. Реализация доступа к данным должна иметь определенный интерфейс, который реализует, от которого зависит только прикладной код приложения. Выбранный вами код инфраструктуры (ADO.NET, NHibernate, NDatabase и т. Д.) Должен иметь интерфейсы, от которых зависит только ваш код доступа к данным. Когда эти инфраструктурные интерфейсы (IDBConnection, ISession, IDatabase и т. Д.) Доступны и правильно используются, вы можете затем смоделировать эти интерфейсы в своих модульных тестах, используя предпочитаемый инструмент для моделирования. Это дает вам более качественный код доступа к данным, который был протестирован модульно (интерфейсы инфраструктуры моделирования), протестирован на интеграцию (с базой данных REAL) и имеет более низкое сетевое соединение.

Одно замечание: по моему мнению, неприятный запах кода следует опасаться, когда код, связанный с доступом к данным, выходит за пределы уровня доступа к данным (или персистентности). Например, если вы видите, что соединения, команды, сеансы и т. Д. Используются выше, чем реализация класса доступа к данным, это пахнет нарушением разделения проблем.

...