ASP.NET: EntityFaker helper for unit-testing или помощник для написания Unit-тестов
Сайтостроение | создано: 05.08.2014 | опубликовано: 06.08.2014 | обновлено: 13.01.2024 | просмотров: 5768
Писать тесты при написании программ (сайтов, библиотек, контролов) признак хорошего тона в программировании. А если учесть, что написание тестов требуют достаточно много времени, то помощник в этом деле не помешает.
Что это такое EntityFaker
Это библиотека создана для упрощения написания тестов для ASP.NET MVC, но я уверен, что вы можете использовать ее и в других типах проектов. Генератор призван создавать сущности и заполнять примитивные типы свойств (только открытые) простыми данными.
Инструменты и всё такое
Я буду использовать Visual Studio 2013 Ultimate, проект на платформе ASP.NET MVC 5. В отдельном проекте отведенном под тесты у меня для генерации заглушек используется RhinoMocks. Для написания тестов я использую на этот раз MSTests.
Как установить
Для того чтобы в вашем тестовом проекте появилась возможность использовать генератор, надо установить nuget-пакет:
PM> Install-Package EntityFaker Installing 'EntityFaker 1.0.1'. Successfully installed 'EntityFaker 1.0.1'. Adding 'EntityFaker 1.0.1' to Calabonga.Mvc.Lipix. Successfully added 'EntityFaker 1.0.1' to Calabonga.Mvc.Lipix. PM>
Это пример установки в мой проект.
Пример использования
Допустим у меня есть некий класс, который мне нужно использовать в тестах.
public class Picture : IdentityBase {
[Required]
[StringLength(50)]
[Display(ResourceType = typeof(Resources.Resources), Name = "Route")]
public string Name { get; set; }
[Display(ResourceType = typeof(Resources.Resources), Name = "DisplayName")]
[StringLength(50)]
public string DisplayName { get; set; }
[Display(ResourceType = typeof(Resources.Resources), Name = "Description")]
[DataType(DataType.MultilineText)]
public string Description { get; set; }
[Required]
[Display(ResourceType = typeof(Resources.Resources), Name = "CreatedAt")]
[DataType(DataType.DateTime)]
public DateTime CreatedAt { get; set; }
[Display(ResourceType = typeof(Resources.Resources), Name = "LibraryId")]
public int LibraryId { get; set; }
[ForeignKey("LibraryId")]
public virtual Library Library { get; set; }
[Display(ResourceType = typeof(Resources.Resources), Name = "DisplayNameEn")]
[StringLength(50)]
public string DisplayNameEn { get; set; }
[Display(ResourceType = typeof(Resources.Resources), Name = "DescriptionEn")]
[DataType(DataType.MultilineText)]
public string DescriptionEn { get; set; }
public string Src {
get {
var library = string.Empty;
if (Library != null) {
library = Library.Name;
}
return string.Format("/gallery/{0}/{1}", library, Name);
}
}
}
Также у меня есть некоторый слой логики, который управляется этими классами. Я покажу интерфейс:
public interface IImagesProcessor
{
PagedList<Category> GetCategories(int pageIndex, int defaultPageSize);
PagedList<Library> GetLibraries(int pageIndex, int defaultPageSize, Category category);
PagedList<Picture> GetPictures(int pageIndex, int defaultPageSize, string library);
Picture GetById(int id);
void Delete(Picture item);
void Update(Picture item);
}
Unit-тесты в примерах
Итак, для того чтобы было проще описать как использовать этот помощник, сразу приведу пример теста. Для начала метод инициализации теста:
[TestInitialize]
public void Setup() {
var context = MockRepository.GenerateStub<IContext>();
context.Categories = DataContextBuilder.GetCategoriesDbSet();
context.Pictures = DataContextBuilder.GetPisturesDbSet(_picturesCount);
var logNotify = MockRepository.GenerateStub<ILogNotifyService>();
var fileService = MockRepository.GenerateStub<IFileService>();
_processor = new ImagesProcessor(context, fileService, logNotify);
}
Немного прокомментирую приведенный листинг. Строка 3 – создается заглушка для IContext, в моем проекте этот интерфейс представляет DbContext. Вот этот интерфейс для ознакомления:
public interface IContext
{
IDbSet<Category> Categories { get; set; }
IDbSet<Library> Libraries { get; set; }
IDbSet<Picture> Pictures { get; set; }
// много удалено для краткости ...
}
Но не в этом “соль”. Обратите внимание на строки 4-5, где как раз в сгенерированную “заглушку” дополняются данными некоторые свойства, а именно Categories и Pictures. Вот как выглядит билдер:
public static class DataContextBuilder
{
public static IDbSet<Category> GetCategoriesDbSet(int count = 5)
{
return DbSetter<Category>.GetObject(EntityFaker.CreateListOf<Category>(count));
}
public static IDbSet<Picture> GetPisturesDbSet(int count = 5)
{
return DbSetter<Picture>.GetObject(EntityFaker.CreateListOf<Picture>(count));
}
}
Вот самая “соль”. В строке 5 и 10 используется EntityFaker для генерации коллекций сущностей, однако, можно генерировать и единичные сущности. Чтобы было совсем всё понятно, если я захочу создать один объект типа Category, я вызову генератор так:

Как вы видите, ничего хитрого нет, свойства заполняются значением названий свойств с подстановкой номера по порядку по индексу генерации. А если я вызову метод (как в строке 5 предыдущего листинга), то результатом будет:

Для построения простых тестов такое количество данных и такое качество данных полностью удовлетворяет потребностям. Для более сложных тестов (хотя в соответствии с одной и парадигмой Unit-тестирования, тесты должны быть просты, но множественны) придется в созданном классе (-ах) подменить некоторые данные или искать другие варианты генерации. И конечно же, никто не исключает использование Mock-фреймворков.
Внимание: Применение немного изменилось. Теперь для того чтобы использовать генератор, требуется создать его экземпляр и уже у него вызывать методы.