Посоветуйте, как тестить парсер DOM, SAX ...
Есть XML, я её распарсил несколькими способами. Далее необходимо написать к парсерам модульные тесты.
public class ParserDOM {
public static void main(String[] args) throws Exception {
InputStream is = new FileInputStream("c:/myXML.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
dbFactory.setNamespaceAware(true);
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(is);
doc.getDocumentElement().normalize();
System.out.println("Root element :" + doc.getDocumentElement().getNodeName());
NodeList nList = doc.getElementsByTagName("CD");
for (int temp = 0; temp < nList.getLength(); temp++) {
Node node = nList.item(temp);
System.out.println("\nCurrent Element :" + node.getNodeName());
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) node;
System.out.println(" TITLE : " + eElement.getElementsByTagName("TITLE").item(0).getTextContent());
System.out.println(" ARTIST : " + eElement.getElementsByTagName("ARTIST").item(0).getTextContent());
System.out.println(" COUNTRY : " + eElement.getElementsByTagName("COUNTRY").item(0).getTextContent());
System.out.println(" COMPANY : " + eElement.getElementsByTagName("COMPANY").item(0).getTextContent());
System.out.println(" PRICE : " + eElement.getElementsByTagName("PRICE").item(0).getTextContent());
System.out.println(" YEAR : " + eElement.getElementsByTagName("YEAR").item(0).getTextContent());
System.out.println();
}
}
}
}
Ребята посоветуйте какую то литературу, ссылки, либо может есть у кого то пару примеров. К чему именно необходимо писать модульные тесты в данном классе(инициализация объектов, или только к вызовам обьекта doc)
30 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарівгромко назвать это «XML парсером». Скорее, узкозаточенный парсер вполне опредленной конфигурации.
внутри.касательно тестов, кроме того, что уже подсказывали(распарсить, сгенерировать обратно и сравнить), предлагаю еще добавить тест на не валидные данные. начиная от глобальных проблем(файл не найден) и заканчивая неполными данными.
вон, у тебя в классе написано throws Exception. для чего, как думаешь?
вообще, идеальна для тестирования функция, которая все данные берет в параметрах конструктора/методов.
то есть, не дожно быть захардкодженного
а должен быть параметр(какого типа?), который предоставить коду класса доступ к данным.
спасибо за совет. throws Exception — предупреждаю о куче exceptions (IOException, ParserConfigurationException, SAXException) которые могут вылететь с метода main
ага. а в каких случаях те самые Exception вылетают?
я к чему веду — эти ситуации тоже надо тестировать.
Поменьше слушайте тех, кто не может написать, а только ругается, они просто потеряли навыки. Пишется примерно так:XML-ка лежащая по нужному пути:
Вот наша
<SomeRootElement> <CD id="1"> <TITLE>Rhapsody of fire</TITLE> <ARTIST>Luca Turilli</ARTIST> <COUNTRY>Italy</COUNTRY> <COMPANY>Producer Valentin(c)</COMPANY> <PRICE>19.99$</PRICE> <YEAR>2002</YEAR> </CD> </SomeRootElement>Бин, который содержит данные и парсер их запихивает в этот бин. Кстати геттеры/сеттеры не для прикола нужны, а в них можно что-то полезное засунуть. Equals нужно, т.к. тестовый класс сравнивает оба объекта по equals, hashcode переопределять вместе — good practicepackage org.dou.lalala; /** * Date: 6/18/14 * Time: 4:21 PM */ public class Song { private String title; private String artist; private String country; private String company; private String price; private String year; public Song() {} public Song(String title, String artist, String country, String company, String price, String year) { this.title = title; this.artist = artist; this.country = country; this.company = company; this.price = price; this.year = year; } public String getTitle() { return title; } public void setTitle(String title) { checkForEmpty(title); this.title = title; } public String getArtist() { return artist; } public void setArtist(String artist) { checkForEmpty(artist); this.artist = artist; } public String getCountry() { return country; } public void setCountry(String country) { checkForEmpty(country); this.country = country; } public String getCompany() { return company; } public void setCompany(String company) { checkForEmpty(company); this.company = company; } public String getPrice() { return price; } public void setPrice(String price) { checkForEmpty(price); this.price = price; } public String getYear() { return year; } public void setYear(String year) { checkForEmpty(year); this.year = year; } private void checkForEmpty(String value) { if (value == null || value.length() == 0) { throw new IllegalArgumentException("Value shouldn't be empty"); } } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Song song = (Song) o; if (artist != null ? !artist.equals(song.artist) : song.artist != null) return false; if (company != null ? !company.equals(song.company) : song.company != null) return false; if (country != null ? !country.equals(song.country) : song.country != null) return false; if (price != null ? !price.equals(song.price) : song.price != null) return false; if (title != null ? !title.equals(song.title) : song.title != null) return false; if (year != null ? !year.equals(song.year) : song.year != null) return false; return true; } @Override public int hashCode() { int result = title != null ? title.hashCode() : 0; result = 31 * result + (artist != null ? artist.hashCode() : 0); result = 31 * result + (country != null ? country.hashCode() : 0); result = 31 * result + (company != null ? company.hashCode() : 0); result = 31 * result + (price != null ? price.hashCode() : 0); result = 31 * result + (year != null ? year.hashCode() : 0); return result; } }Сам парсер, который парсит в бин. Если нужно много песен изXML-ки брать, есть коммент
package org.dou.lalala; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.w3c.dom.Node; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; /** * Date: 6/18/14 Time: 4:00 PM */ public class CustomDomParser { public static Song parseXMLToSong(String path) throws Exception { DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); Document doc = docBuilder.parse(path); //change this piece of code to a loop in case you need to iterate over //multiple songs, int this case your should return array or list or set instead //of Song bean Node cd = doc.getElementsByTagName("CD").item(0); NodeList cdAttributes = cd.getChildNodes(); Song parsedSong = new Song(); for (int i = 0; i < cdAttributes.getLength(); i++) { Node node = cdAttributes.item(i); if ("TITLE".equals(node.getNodeName())) { parsedSong.setTitle(node.getTextContent()); continue; } if ("ARTIST".equals(node.getNodeName())) { parsedSong.setArtist(node.getTextContent()); continue; } if ("COUNTRY".equals(node.getNodeName())) { parsedSong.setCountry(node.getTextContent()); continue; } if ("PRICE".equals(node.getNodeName())) { parsedSong.setPrice(node.getTextContent()); continue; } if ("YEAR".equals(node.getNodeName())) { parsedSong.setYear(node.getTextContent()); continue; } if ("COMPANY".equals(node.getNodeName())) { parsedSong.setCompany(node.getTextContent()); } } return parsedSong; } }тестовый класс, у вас должен быть подключен junit-4.11
package org.dou.lalala; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; /** * Date: 6/18/14 * Time: 4:31 PM */ public class CustomDomParserTest { @Test public void testSongIsNotNullSimple() throws Exception { //given Song expectedSong = new Song(); expectedSong.setTitle("Rhapsody of fire"); //when Song parsedSong = CustomDomParser.parseXMLToSong("c:\\myXML.xml"); //then assertNotNull(parsedSong); assertEquals(expectedSong.getTitle(), parsedSong.getTitle()); } @Test public void testSongIsNotNullComplex() throws Exception { //given Song expectedSong = constructExpectedSong(); //when Song parsedSong = CustomDomParser.parseXMLToSong("c:\\myXML.xml"); //then assertNotNull(parsedSong); assertEquals(expectedSong, parsedSong); /*assertEquals(expectedSong.getTitle(), parsedSong.getTitle()); assertEquals(expectedSong.getCompany(), parsedSong.getCompany()); assertEquals(expectedSong.getCountry(), parsedSong.getCountry()); assertEquals(expectedSong.getPrice(), parsedSong.getPrice()); assertEquals(expectedSong.getArtist(), parsedSong.getArtist()); assertEquals(expectedSong.getYear(), parsedSong.getYear());*/ } private Song constructExpectedSong() { return new Song("Rhapsody of fire", "Luca Turilli", "Italy", "Producer Valentin(c)", "19.99$", "2002"); } }Итого 39 минут на всё про всё.
Тупанул с equals и дебажил минут 10. Всегда внимательно относитесь к нему и к hashcode еще внимательней.
Будут вопросы, пожелания — пишите прямо на форуме.
Удачи.
Коментар порушує правила спільноти і видалений модераторами.
Ваши претензии без действующего кода с вашей стороны = пук в лужу.
зачем вы написали готовое решение к учебному заданию?
upd дочитал до конца: так что тестовому, а не учебному.
Женя, в этом решении все равно автору придется разобраться до собеседования, так что ничего плохого вроде как нет.
какая разница между самостоятельным поиском решения и чтением готового ответа?
вы н замечали, что уже решенные проблемы кажутся простыми?
Да, Женя, также, до Prom’а, я часто замечала, когда на мои вопросы, начинающего инженера, часто ответы были разбросаны по разным контекстам, которые я никак не могла слепить в кучу у себя в голове, и чувствовала себя полной дурочкой. А если бы было решение, даже пусть не на 100% покрывающее проблему, было бы гораздо легче, так как сама бы выбирала свой путь в изучении материала. Вообщем-то это и стало причиной того, что я поддержала хороший поступок, как я считаю, Gabriel’а.
Огромная Вам благодарность! Спасибо))
Всегда рад, будут вопросы, проблемы, пожелания — пишите сразу на форуме. Мне в ученичестве помочь было некому, были лишь Петросяны кругом.
Петросяны уже давно завели своих Степаненко и размножаются... страшно представить что будет дальше.
А мы вчера на курсах проходили паттерн Interpretator. ( Это подсказка по теме... )
Паша, возможно и не сознательно, но помойму Вы ввели человека в заблуждение. Либо пролейте пожалуйста свет на Ваше высказывание.
Используя данный патерн с regex можно написать парсер(свой а не встроенный). Тестирование будет заключается в3-4 строки. Да мой совет более самому парсеру а не тестированию подходит. Но даже я как джун вижу что в мейне столько кода не должно быть.
.
P.S. Но судя то вашему «паресеру», вам стоит начать с чего-то вроде «основы программирования».
спс, а в чем недостатки парсера? подскажите, что неверно, буду благодарен.
Неконфигурируемый, что усложняет тестирование; как для парсера писать сообщения напрямую в system.out плохой подход (лучше использовать интерфейс logger фреймворка. Почему — в интернете много информации на этот счет). Это то, что бросилось мне в глаза сразу.
спс)
Если уж настолько примитивно, то хотя бы научись перебирать дерево циклом по Node.getNextSibling()
И таким нехитрым способом ты можешь перебирать мелкиеXML-ки. Для крупного — ты многократно (!!!) просматриваешь одни и те же узлы. А потому первое что делают при парсинге XML — это парсят его в нормальный класс, в Properties или ещё какую удобную для програмирования структуру. Либо если это какая-то типичная XML-структура более высокоуровневого протокола (тот же самый SOAP) — то там есть свои парсеры, возвращающие честный класс.
Тестить то что ты написал — мягко скажем сложновато. Если ты всё выбрасываешь в System.out, то где ты собираешься искать выходные данные для теста?
Ещё более железобетонный вариант — положить ПРИМЕР XML прямо в проект. Это поможет разработчику увидеть что от него ждут, это поможет при передаче проекта другому разработчику, и конечно же этот пример будет отдан вместе с документацией автору кода, который собственно и будет посылать XML.
И тот же файл будет лететь на автоматический тест. И из него же будут делать копию для ручного теста ежели таковой понадобится.
Самый простой пример крупнокалиберного теста — это забилдить XML обратно из распарсенного класса, и убедиться что в нём всё есть. Можно запустить полученный XML обратно на парсер, и убедиться что результат идетничен с точностью до байта [контрольной суммы] или проверить более сложным текстовым анализом где ошибка.
Более правильно — предоставить этот тест на публичный интерфейс в продакшен. Чтобы разработчик фронтенда мог со своей стороны его запустить, и найти когда разработчик серверной части что-то накосячил с конфигом. Это позволяет снизить требования к опыту разраба фронтенда, то бишь быстро отлавливать типовые ашыпки.
а вот за это благодарен))
Тестовое задание что ли?
да
И он его по ходу уже провалил. Угадай с одного раза, те кто ему задание дал — не сидят ли на DOU?
Я бы на их месте дал ему сейчас и решение, но с какой-нить уникальной заковыкой в коде. И кто этот код принесёт — попадает в чёрный-чёрный список.
Мораль: если уж собирается читить — заказал бы на фрилансе. И то же самое когда уже устроился на работу: что-то не получается — дал доллар индусу и вуаля. А так... спалился поцаньчик :)
Во первых: я не просил, что бы задание решили за меня, я лишь попросил литературу, ссылки, примеры....Что вы видите в этом плохого???
Во вторых: Компания прекрасно знает, что я пока не знаю данную тему, и буду её учить.
Так что не*рена я не спалился, поцаньчик)))
а спросить на форуме это не по-пацански?
На форуме где работодатель сидит? Ещё б в саппорт компании написал :)