Как можно это все проверить? Мои мысли:
Внести фейковые данные в базу данных.
Добавить данные через тест.
Задать значения для проверки.
Сравнить данные для проверки с данными из БД?
Как это примерно реализовать? Просто с дата сервисами не работал особо вот и возникло затруднение.
public class NewsDataService {
private News news;
private List
public NewsDataService() throws ClassNotFoundException, SQLException {
db = new DatabaseConnector();
newss = new ArrayList
}
public News getNews(int id) throws SQLException {
result = db.query("SELECT * FROM news WHERE idnews = " + id);
result = db.query("SELECT * FROM news WHERE idstudent = " + id);
result = db.query("SELECT * FROM news WHERE idgroup = " + id);
while (result.next()) {
news.setDate(result.getString("date"));
news.setTitle(result.getString("title"));
news.setContent(result.getString("content"));
}
return news;
}
public News findByTitleNews(String title) throws SQLException {
result = db.query("SELECT * FROM news WHERE title ='" + title + "'");
while (result.next()) {
news.setTitle(result.getString("title"));
news.setId(result.getInt("idnews"));
news.setId(result.getInt("idgroup"));
news.setId(result.getInt("idstudent"));
news.setDate(result.getString("date"));
news.setContent(result.getString("content"));
}
return news;
}
public List
}
return newss;
}
public void save(News news) throws SQLException {
String sql = "INSERT INTO news('title', 'content', 'date') "
+ "VALUES ('" + news.getTitle() + "', '" + news.getContent()
+ "', '" + news.getDate() + "',?);";
PreparedStatement pstmt = db.getConnect().prepareStatement(sql);
pstmt.execute();
pstmt.close();
System.out.println(sql);
System.out.println("News successful inserted");
}
}
Ответ
Протестировать текущий вариант класса NewsDataService - не самая тривиальная задача для решения, попробую объяснить почему.
В процессе написания данного класса вы решили заинкапсулировать всю логику работы с БД внутри кода, дойдя до крайне низкого уровня - ручного составления SQL запросов. И теперь ваш класс служит крайне узкоспециализированной цели, поскольку он умеет только лишь создаваться и отвечать на запросы вида "дай мне сущность с id" и "сохрани такую-то сущность"
Чтобы улучшить этот аспект кода (coupling), я бы порекомендовал бы вам почитать про Inversion of Control, Dependency Injection и про ORM.
Я могу предложить 3 различных подхода к тестированию текущего варианта реализации NewsDataService, которые вполне как можно скомбинировать в тех или иных пропорциях
Воспользуйтесь sandbox-based подходом - возьмите легковесную базу данных, заполните ее реальными значениями и напишите юнит-тесты без моков вообще. Вообще говоря, если бы вы писали такие тесты перед написанием кода (следуя методологии TDD), то вам бы сразу открылись многие минусы и неудобства использования написанного класса. Специально для таких целей можно использовать DbUnit, позволяющий упростить создание сендбоксовой базы данных и написание Setup / Teardown методов.
Следуя принципам IoC, инициализируйте ваш DatabaseConnector в другом месте, а в NewsDataService прокидывайте его через конструктор. Это, во-первых, снимает с NewsDataService ответственность за инициализацию подключения, а во-вторых упрощает тестирование. Вот здесь уже сам по себе DatabaseConnector можно подменить mock-объектом, который будет эмулировать часть функциональности, например, на любой запрос SELECT будет возвращать предопределенную пачку новостей.
Подход не самый лучший, потому что mock-объект должен быть предельно простым (иначе потребуются тесты на тесты), а этот факт сильно сковывает руки при тестировании. То есть, грубо говоря, вы не можете и не должны парсить запрос в вашем mock'e, поэтому максимум, что вы можете делать с его помощью - это разделять запросы SELECT / UPDATE, возвращая на них какую-нибудь заранее заданную чушь, ну и, например, проверять, что databaseConnector.query вообще был вызван.
Общее правило достаточно простое - если код mock'a вызывает вопросы о том, правильно ли он работает для всех случаев, то это - плохой mock Иногда, естественно, бывают ситуации, что без сложного mock'a не обойтись, но в таком случае нужно писать тесты на этот самый mock, что обычно бывает нежелательным.
Выделить генерацию SQL запросов в отдельный класс типа SqlQueryProvider. В таком случае ваш текущий код начнет меняться примерно в следующую сторону:
... databaseConnector.query(sqlQueryProvider.getQueryToRetrieveById(...));
Такой подход уже позволяет отдельно покрыть тестами генерацию запросов, и, зная, что запросы к генерируются корректно, серьзно сэкономить на реальном тестировании NewsDataService. Опять же, для тестирования NewsDataService в таком случае может пригодиться mock на SqlQueryProvider
Несколько референсов по теме:
Unit Testing Database Code
Testing With DbUnit
How do I unit test jdbc code in java?
Всегда, кстати, хотелось посмотреть, как авторы советов типа "возьмите XYZMock, да заmock'айте эту обертку над БД и протестите, делов то" делают это на практике и сделали бы это, достанься им legacy код типа NewsDataService.
Комментариев нет:
Отправить комментарий