Будьте внимательны при следовании этому совету на этой странице.Я сделал, и это не сработало слишком хорошо, и я немного сгорел.
Вам НУЖНО проверить свои бизнес-классы с помощью интеграционных тестов (тестов, использующих реальную базу данных) вместо чистых модульных тестов (с использованиемв хранилище данных памяти) вместо юнит-тестов.Причина в том, что вы закончите с вашими модульными тестами, дающими ложные проходы и ложные отрицания.
Возьмите следующий пример.Скажем, ваша бизнес-логика хочет запрашивать любые запросы, которые были сделаны на сегодняшний день.В бизнес-логике я бы написал:
var requests = _unitOfWork.Requests.Where(x => x.RequestDate.Date = DateTime.Now.Today).ToList();
Это будет хорошо работать при работе с объектами памяти, но вызовет NotImplementedException
, потому что EF не может эффективно обработать этот тип запроса.Существует множество запросов Linq, которые не поддерживаются Entity Framework, но вы не поймаете их, если не будете выполнять интеграционные тесты.Таким образом, ваши модульные тесты теперь дают вам ложные срабатывания, они утверждают, что это работает, когда это действительно не так.
Теперь возьмем случай, когда ваша бизнес-логика хочет запрашивать запросы, которые были сделаны конкретным пользователем.Скорее всего, ваша бизнес-логика сделает это, в результате вы получите оператор Linq, такой как:
var requests = _unitofWork.Requests.Where(x => x.UserId == userid).ToList();
Проблема с этим запросом состоит в том, что для того, чтобы настроить модульный тест на прохождение, вы должны иметь знанияреализации бизнес-логики.Я имею в виду следующее: если у вас есть следующий модульный тест для этого:
[TestMethod]
public void Can_Retrieve_User_Requests()
{
// Setup
var user = new User();
var req1 = new Request();
user.Requests.Add(req1);
_unitOfWork.Add(user);
_unitOfWork.Add(req1);
_unitOfWork.Commit();
// Act
var result = BusinessLogicClass.GetRequestsByUserId(user.Id);
// Assert
Assert.IsNotNull(result);
Assert.AreEqual(1, result.count);
}
Этот модульный тест работает и будет проходить как есть (все остальные аспекты работают, конечно), если _unitOfWork
использует вашСистема Entity Framework.
Если вы используете единицу работы в памяти, это не удастся по двум причинам.Во-первых, user.Id
не задано, 99% идентификаторов времени будут сгенерированы Entity Framework.Даже если вы явно установите user.Id = X
, это все равно не будет выполнено, потому что вам также нужно установить request.UserId
.В EF поле request.UserId
будет автоматически заполняться при создании нового отношения, но этого не произойдет при использовании набора данных в памяти.Это означает, что вы должны точно знать, что GetRequestsByUserId()
реализует запрос, посмотрев на поле Request.UserId
вместо Request.User.Id
, и это также означает, что изменение вашего модульного теста для прохождения в этом случае завершится неудачей, если вы измените свой запросиспользовать Request.User.Id
, даже если бизнес-логика и результат в EF практически одинаковы.
Один последний пример - это то, что происходит, если в поле вашей базы данных недостаточно места для хранения длинной строки (EFCodeFirst по умолчанию имеет длину строки в БД varchar (128)).Если у вас есть тест с более чем 128 символами, ваше хранилище данных в памяти будет хорошо хранить строку, но EF сделает исключение, потому что она слишком длинная.
TLDR : в тестах модулей памятидля запросов данных и хранения данных не даст вам уверенности в том, что ваше приложение работает правильно.Вам все еще нужно создавать интеграционные тесты, но ваши интеграционные тесты должны будут в любом случае проверять 99% того, что охватывают ваши юнит-тесты, и, таким образом, это удвоит ваши усилия по TDD, замедлит вас и затруднит сопровождение тестов.
Вместо этого интеграционные тесты с Sql Server Compact Edition дадут вам подтверждение того, что ваша бизнес-логика не только работает правильно, но и корректно работает с действующей базой данных.
В качестве примечания яговорить о тестировании бизнес-логики с помощью интеграционных тестов.Тестирование контроллеров MVC должно проводиться только на реальной базе данных, если контроллеры действительно обращаются к базе данных напрямую (что не должно быть imho, контроллеры MVC должны вызывать ваши бизнес-классы для выполнения операций с БД), и если контроллеры не 'Если говорить напрямую с базой данных, то вы можете просто использовать среду моделирования, такую как Moq, для моделирования памяти ваших бизнес-классов (поскольку они уже проверены с помощью интеграционных тестов).