Страницы

Поиск по вопросам

вторник, 8 января 2019 г.

JUnit тесты для DataService

Как можно это все проверить? Мои мысли: Внести фейковые данные в базу данных. Добавить данные через тест. Задать значения для проверки. Сравнить данные для проверки с данными из БД? Как это примерно реализовать? Просто с дата сервисами не работал особо вот и возникло затруднение. public class NewsDataService { private News news; private List newss; private DatabaseConnector db; private ResultSet result;
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 findAllNews() throws SQLException { result = db.query("SELECT * FROM news"); while (result.next()) { news.setTitle(result.getString("title")); news.setId(result.getInt("idnews")); news.setId(result.getInt("idgroup")); news.setId(result.getInt("idgroup")); news.setDate(result.getString("date")); news.setContent(result.getString("content"));
}
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.

Как найти объект в объекте?

Здравствуйте. Допустим, у нас есть некий объект. Его структуру и то, что внутри, мы не знаем, но знаем, что там должен быть, например, объект innerObject, который может находится где угодно внутри. Вот пример объекта: var someObj1 = { io1: {sIo1:{ssIo01:'что-то'}} oi2: { sIo1:{ innerObject: {/*внутренности объекта*/} } } } И структура этого объекта и то, где будет находиться наш innerObject, нам не известно. Известно еще то, что innerObject находится НЕ в массиве. Как найти в некотором объекте, объект innerObject? PS Без использования каких-либо библиотек.


Ответ

function checkInObject( obj, name ) { var res = null; for( var i in obj ) { if(obj.hasOwnProperty(i)) { if(i === name) { res = obj[i]; break; } if(obj[i] && obj[i].constructor === Object) { var check = checkInObject( obj[i], name ); if( check ) { res = check; break; } } } } return res; }
var someObj1 = { io1: {sIo1:{ssIo01:'что-то'}}, oi2: { sIo1:{ innerObject: { test : "done" } } } }
console.log(checkInObject( someObj1, 'innerObject' ).test); // -> done

JSON. Пределы возможного

Доброго времени суток, ув. сообщество. Перейду сразу к делу: Какой максимальный объём JSON данных можно забрать с сервера? Неограниченно Какой максимальный объём JSON данных можно забрать с сервера без вреда для него и клента? Ограниченно железом Какой максимальный объём JSON данных можно хранить на клиенте? Какой максимальный объём JSON данных можно хранить на клиенте без вреда для системы? 2 Гб ± ... Как можно оптимизировать загрузку большого объёма данных(кроме Lazy loading)? Параллельная загрузка Как можно оптимизировать хранение большого объёма данных на клиенте(кэширование, может Local Storage)? Заранее благодарю всех откликнувшихься. UPD: JSON Compression algorithms - что можете сказать об этом? Чепуха © @karmadro4 @rnd_d, данные я собираюсь рендерить, не все сразу конечно, но чтобы не тратить время ещё и на загрузку этих данных, они мне нужны ввиде Backbone.Collection на клиенте @AlexWindHope, на сколько мне известно, кол-во параллельных запросов на один домен ограничено, в Opere например, по умолчанию стоит 16, но можно увеличить до 128, как обстоят дела в других браузерах не знаю.


Ответ

Знаю что кто-то писал java софтину, где обрабатывали > 2гб json'a( что привело к необходимости фикса JSON парсера 4 java ). Так что юзать можно по полной. С учетом того, что в большинстве браузеров парсинг JSON реализован на нативном уровне - скорость тоже на уровне. Вообще если вы пишите приложение, где удобно было бы использовать json формат данных - стоит посмотреть в сторону noSQL документно-ориентированных бд (mongoDB, couchDB). По поводу хранения большего количества данных - Local storage + запрос вида - не поменялись ли данные(если поменялись, естественно, тянем новые), при желании можно придумать что-то посложнее и поинтереснее, но не думаю что в этом есть смысл, а если и будет - то это уже отдельный вопрос.

Изменить цвет части текста в TextView

Нужно сделать первые буквы красными, можно через ресурсы, можно в коде! Как это сделать?


Ответ

С помощью span TextView textView = (TextView)findViewById(R.id.textView);
final SpannableStringBuilder text = new SpannableStringBuilder("Text"); final ForegroundColorSpan style = new ForegroundColorSpan(Color.rgb(255, 0, 0)); text.setSpan(style, 0, 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE); textView.setText(text);

Как обратится к приватной переменной из другого класса в Java

Например есть код: class B { private int i = 22; }
class A { // тут код который выводит переменную i } Условие: класс B нельзя менять. класс А можно менять (т.е наследовать класс B и т.д)


Ответ

Через Reflection B b = new B(); Class clazz = B.class; Field iField = clazz.getDeclaredField("i"); iField.setAccessible(true); int fieldValue = iField.getInt(b); System.out.println("i = " + fieldValue);

Возможно ли управлять распределением потоков по ядрам процессора?

Всем добрый день! Рассматриваю возможности реализации нового сервера, и пока остановилась на модели с созданием пула потоков. Однако поступила информация, что при такой работе сервера на многоядерной системе, определенные потоки будут закреплены за ядрами сразу и перераспределения их не будет, пока они не будут уничтожены, то есть возможна ситуация, когда часть пула потоков, которая на данный момент никаких активных действий не производит, будет висеть на одном ядре, и оно фактически будет простаивать, в то время, как второе ядро будет загружено несколькими активными потоками. Если кто-то в курсе, подскажите плиз, действительно ли это так, и есть ли какой-то способ управлять распределением потоков по ядрам, чтобы загружать их более-менее равномерно? Может кто-то может полезной ссылочкой поделиться применительно к unix - я ничего толкового пока не нашла по этому вопросу.


Ответ

Ручное распределение потоков по ядрам нужно только в очень исключительных случаях. Система будет перераспределять потоки между ядрами, как ей кажется правильно. И может перебросить рабочий тред с одно ядра на другое но в 99% это не нужно. Давайте представим некую виртуальную систему с 16 ядрами и 100 потоками. и 10 из них активно работает, занимая при это 10 ядер. Остальные 90 сидят тихонько на оставшихся 6. Вопрос, есть ли смысл перебрасывать активный поток на другое ядро? Ответ - нет. Только хуже сделаем (накладные расходы на переключение). Поэтому система будет пытаться сохранить поток на своем ядре. Вариант, когда ядер 2 и 100 потоков (из них 10 активных). В этом случае загружены будут точно два ядра. Причем выиграш от того, что есть 10 активных потоков будет отрицательный. Именно по этой причине, когда создают пул потоков, которые нагружены одинаково, не делают их больше кол-ва ядер+1. Потому что при дальнейшем увеличении кол-ва потоков будет только падение производительности (накладные расходы на переключение. Процессор только тем будет и заниматься, что переключать контексты потоков). В случае одного ядра, не рекомендуется создавать более 16 потоков на процесс (это конечно устаревшая информация, данная Борландом в году так 1995-1997 и в век двухядерных процессоров у каждой домохозяйки в ноуте и в планшете она малоактуальна). Но есть вариант, когда много потоков может улучшить задачу - это когда потоки занимаются малоактивной работой. Но преимущество только одно - упрощается логика кода. Но это сильно зависит от задачи. А теперь подсуммируем. Если у вас сервер с 2 ядрами, то на данный момент это не сервер, а домашний компьютер. Будете делать пул потоков - сделайте возможность регулировать кол-во потоков в пуле и проведите замеры. Очень часто, выставив правильное кол-во потоков, можно сильно ускорить задачу. А в некоторых случаях может выяснится, что оптимально будет работать только при одном потоке. Не доверяйте русскоязычному переводу англоязычной документации. В спорных случаях обращайтесь к английскому оригиналу. У меня был случай, когда из за неточностей в одно слово в переводе мана по select смысл очень сильно менялся

Как преобразовать Byte[] в Int32?

Есть Byte[] buffer большого размера, в который читается значение типа Int32 (из tcp). Как из этого Byte[] (или его фрагмента) получить Int32? Можно брать 4 элемента массива и складывать, предварительно сдвинув биты, или есть какое-то встроенное средство C# для этого? Может глупый вопрос, но все-таки...


Ответ

Для конвертации базовых типов в массивы байт и обратно есть класс BitConverter using System;
public class Example { public static void Main() { // Create an Integer from a 4-byte array. Byte[] bytes1 = { 0xEC, 0x00, 0x00, 0x00 }; Console.WriteLine("{0}--> 0x{1:X4} ({1:N0})", FormatBytes(bytes1), BitConverter.ToInt32(bytes1, 0)); // Create an Integer from the upper four bytes of a byte array. Byte[] bytes2 = BitConverter.GetBytes(Int64.MaxValue / 2); Console.WriteLine("{0}--> 0x{1:X4} ({1:N0})", FormatBytes(bytes2), BitConverter.ToInt32(bytes2, 4));
// Round-trip an integer value. int original = (int) Math.Pow(16, 3); Byte[] bytes3 = BitConverter.GetBytes(original); int restored = BitConverter.ToInt32(bytes3, 0); Console.WriteLine("0x{0:X4} ({0:N0}) --> {1} --> 0x{2:X4} ({2:N0})", original, FormatBytes(bytes3), restored); }
private static string FormatBytes(Byte[] bytes) { string value = ""; foreach (var byt in bytes) value += String.Format("{0:X2} ", byt);
return value; } } // The example displays the following output: // EC 00 00 00 --> 0x00EC (236) // FF FF FF FF FF FF FF 3F --> 0x3FFFFFFF (1,073,741,823) // 0x1000 (4,096) --> 00 10 00 00 --> 0x1000 (4,096) UPD. И не забывайте про порядок байтов. В случае с TCP/IP, вероятно, придется изменить порядок байтов на обратный. Узнать какой порядок используется в текущей системе можно через свойство того же класса BitConverter.IsLittleEndian