Как проверить функции со сложными взаимодействиями данных - PullRequest
3 голосов
/ 06 июня 2011

В настоящее время я работаю над системой, которая выполняет довольно много функций в стиле отчетности, которые потребляют много разных точек данных и преобразуют их в более крупные, иногда сглаженные выходные данные. Большая часть моего приложения построена на вариации шаблона репозитория. В связи с этим у меня есть набор репозиториев, которые я использую для тестирования сценариев. Проблема, с которой я сталкиваюсь, состоит в том, что взаимодействие между этими точками данных настолько сложное, что быстро становится кошмаром обслуживания для поддержки «фиктивных данных». Вот пример из примера:

public class SomeReportingEntity
{
private IProductRepo ProductRepo;
private IManagerRepo ManagerRepo;
private ILocationRepo LocationRepo;
private IOrdersService OrdersService;
private IEmployeeRepo EmployeeRepo;

public ReportingEntity(IProductRepo ipr, IManagerRepo imr, ILocationRepo ilr, IOrdersService ios, 
    IEmployeeRepo ier){
        //Load these to private vars...
}

    //This is the function that I want to test...
public SomeReportingEntity GetManagerSalesByRegionReport()
{
    //Make a complex join on all sub collections.  These
    //sub collections are all under test individually.
    var MangerSalesByRegionItems = From x in ProductRepo.CurrentProducts()
                              Join y in OrdersService.FutureOrders() On ...
                              Join z in EmployeeRepo.ActiveEmployees() On  ...
                              Join a in LocationRepo.GetAllRegions() On ...
                              Join b In ManagerRepo.GetActiveManagers On ...
                              Select new SomeReportingEntity() With { ... }

    return MangerSalesByRegionItems.ToList();       
}

}

По общему признанию, это очень надуманный пример, но основная идея, на которой я хочу подчеркнуть, состоит в том, что у меня есть несколько репозиториев, к которым я присоединяюсь, и мне нужно создать много тестов, чтобы гарантировать, что этот сложный запрос будет работать, как ожидалось. Из-за того, что операции объединения являются настолько сложными, это делает ОЧЕНЬ трудно поддерживать согласованные данные - тем более, что мне нужно добавить больше ассоциаций и проверить дополнительные точки. Кроме того, мне нужно иметь возможность вводить конкретные состояния записи в макеты (например, у сотрудника, у которого нет назначенного менеджера), чтобы убедиться, что запрос обрабатывает эти ситуации соответствующим образом.

Итак, вот мои вопросы:

  1. Каков наилучший способ «высмеивать» эти данные, чтобы они не были таким кошмаром по вопросам материнства? У меня было много людей, предлагающих создать базу данных в памяти, чтобы поддержать это.
  2. Я действительно страдаю от проблемы архитектуры здесь? В сценариях отчетности я довольно часто оказываюсь в этом паттерне, где беру много разрозненных точек данных и объединяю их в новый гибридный объект. С появлением Linq это очень легко сделать, и у него высокая ясность намерений, но иногда кажется, что я немного изменяю.

Ответы [ 3 ]

1 голос
/ 08 июня 2011

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

С логистической точки зрения я хотел бы рассмотреть одну вещь: создать локальную базу данных для хранения удаленных данных (периодически обновлять с использованием агентов). Это устранит некоторые проблемы вызова удаленных служб и агрегирования их данных на лету. Вы также сможете предварительно обработать некоторые данные в начале.

Когда я использую шаблон репозитория, я связываю его с шаблоном Unit Of Work . Единица работы - это парень, который делает всю работу за вас. Теоретически, ваш UoW может вводить данные из нескольких сервисов и представлять их в репозитории на основе конфигурации.

Для тестирования вы можете использовать InMemoryUnitOfWork, чтобы предоставить все данные в одном месте.

1 голос
/ 06 июня 2011

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

Наши тесты имеют тенденцию выглядеть следующим образом ...

var object1 = XmlUtil.LoadObject1("filename1");
var object2 = XmlUtil.LoadObject2("filename2");

var result = SomeConverter.Convert(object1, object2);

Assert("somevalue", result.Property1);

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

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

0 голосов
/ 08 июня 2011

Вы должны решить, что именно вы хотите проверить.

Один из способов сделать это - притвориться, что вы используете TDD. Представьте, что ваш метод GetManagerSalesByRegionReport не существует (или фактически удалите его). Вам придется:

  1. Написать неудачный юнит-тест. Что проще всего протестировать: вы можете вызвать метод и он не выдает исключение, если с данными нет ничего плохого.
  2. Вам нужно создать метод, пустой. Он должен вернуть void, поскольку вашему тесту не нужно ничего возвращать.
  3. Ваш тест должен пройти.
  4. Добавьте тест, чтобы убедиться, что возвращается List соответствующего типа, даже если ни в одном из под-хранилищ нет данных.
  5. Вам придется изменить метод, чтобы он возвращал ваш тип списка, и вам придется изменить его, чтобы он возвращал null. Ваш тест все равно не пройден, поэтому замените его на пустой List, и он пройдет.

Что осталось? Это INNER соединения, поэтому вы не получите никаких данных обратно, если во всех хранилищах не будет хотя бы одной строки. Итак, проверьте это: создайте тест, в котором каждый репо содержит одну строку и убедитесь, что возвращаемый список содержит соответствующее количество строк. Затем проверьте соответствующие свойства для каждой возвращаемой строки. Затем проверьте, что данные не возвращаются, если в каком-либо репозитории нет строк.

Затем, возможно, проверьте, что произойдет, если некоторые репозитории содержат более одной строки.

Тогда я не знаю, что осталось бы проверить.

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