Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АрхитектураБиологияГеографияДругоеИностранные языки
ИнформатикаИсторияКультураЛитератураМатематика
МедицинаМеханикаОбразованиеОхрана трудаПедагогика
ПолитикаПравоПрограммированиеПсихологияРелигия
СоциологияСпортСтроительствоФизикаФилософия
ФинансыХимияЭкологияЭкономикаЭлектроника

Началось все в 2004 году. Selenium начался с того, что мы сейчас знаем под именем Selenium Core - javascript библиотека, Selenium ide появился значительно позже, в 2006 году. На текущий момент



Selenium

Началось все в 2004 году. Selenium начался с того, что мы сейчас знаем под именем Selenium Core - javascript библиотека, Selenium ide появился значительно позже, в 2006 году. На текущий момент существует около 20 активных эммитеров селениума (т.е. людей, которые активно занимаются его разработкой). Selenium распространяется под лицензией апатч 2.0, эта очень легковесная открытая лицензия. Несколько компаний, которые используют Selenium или активно помогают ему. Среди них стоит отметить гугл, который в последние годы очень много делает для Seleniumа. Существует также другая поддержка, в частности появились книги (на начало 2011 года их было всего 2).

У любого проекта с какого момента начинается стадия, когда тестированию надо уделять все время. Критерии выбора инструмента: 1) возможности (что позволяется сделать инструмент) 2) скорость входа (как быстро можно начать его использовать) 3) легкость поддержки и изменения существующих тестов 4) стоимость инструментов и персонала

Часто получается так, что вам достается довольно-таки “хардкорный” проект, в нем очень много кода, и не всегда он самого лучшего качества и очень часто он далеко не объектно-ориентированный, не аспектно-ориентированный, и внесение в него каких-то поправок занимает очень много времени, не то чтобы их даже покрывать тестами. Часто это даже практически невозможно. Покрыть такой код тестом очень тяжело. В большинстве случаев рефакторинг этого кода займет гораздо больше времени чем, если написать его просто напросто с нуля. И очень часто заказчик, либо сдача проекта имеет под собой контекст того, что код должен быть всегда рабочим. И без тестов гарантировать это при сдаче проекта нереально. Но что делать когда нет достаточно времени на написание полноценных тестов, а тестировать все таки нужно? Для этого можно применять Selenium. Что такое Selenium? Selenium это определенный проект, который состоит из подпроектов.

1ый проект это Selenium Core. Это JavaScript Framework, с которого вообще в целом начался этот проект. Его задача была интерпретировать, давать возможность на JavaScript-e описывать последовательные действия пользователя и таким образом проводить какие-то сверки и действительно убеждаться в том, что проект работает, формы отправляются, и с клиент-сайта быть уверенным, что работает и бизнес логика на стороне сервера.

Selenium Core: Javascript библиотека, чистый JavaScript. Работает с любыми браузерами. Все тесты будут в виде html, складываются в определенную папочку.



Selenium Core: сложность ненамного отличается от ide. Основная проблема ide отпадает, нет привязки к браузеру. Основная проблема в core. Результаты можно просмотреть только в окошке браузера, т.е. если окошко осталось, то все хорошо, а если браузер упал по какой-то причине, то все тесты с ним тоже. Если тестов большое количество, то время их работы очень продолжительное. Время работы очень сильно зависит от времени исполнения javascriptа. И то что в одних браузерах исполняется за полчаса, в ie исполняется за 10 часов. За 10 часов с браузером точно что-то произойдет, т.е. если он упадет, то с ним и все тесты тоже.

Потом, впоследствии развития появился Selenium IDE. Это очень примитивная среда для написания тестов. Задача была его максимально упростить процесс создания тестов. То есть сократить время, которое вы тратите на покрытие вашей логики тестами. При использовании других систем автоматизированного тестирования, вам нужно учитывать фактор того, что у вас бизнес логика не должна пересекаться с какими-либо отображениями, редиректами. Т.е. конкретно реализовывать проект как паттерны. На практике очень много проектов, которым уже больше 5-10 лет, и в них это отсутствует. Selenium IDE специально создан для того, чтобы покрывать их тестами со стороны клиентской части. И тогда мы, собственно не имеем никакой привязки к коду, который приходит. Тесту, написанному selenium-ом по большому счёту все равно, насколько у вас идеальный код, насколько он быстрый. Т.е. если перед вами огромный проект и вы должны быть уверенными в целостности данных, в его нагрузках, в Selenium в большинстве случаев вам не подойдёт, потому что его задача немного другая.

Selenium IDE

Плагин к фаерфоксу, который записан в макросах. Инструмент с помощью которого можно записывать все действия пользователя в браузере, потом их воспроизводить. Вещь очень простая. Записали, получили нечто, это нечто может повторяться. В браузере выглядит достаточно смешно, компьютер сам что-то стрикает, вводит. Т.е. если вы ввели что-то в форму, записали это, то компьютер потом тоже самое в форму введет.

Что она внутри себя пишет. Последовательные шаги, каждый шаг это какая-то команда, и какие-то аргументы команд. Список команд, доступных в Selenium на слайде.

Как выглядит IDE?

Многие люди используют Selenium?

Так выглядит среда написания тестов Selenium IDE. Коротко о нем. Что это такое? Это не специальное приложение, это extension к FireFox-у. Т.е. фактически данный инструмент не всегда гарантирует свою правильную работу, но в принципе за последние 2 года он стал довольно таки стабильным. Вы через него запускаете некоторые команды через кнопочку record (правый верхний угол-большая красная кнопка). В ней заключен основной функционал Selenium IDE. При нажатии этой красной магической кнопки Selenium начинает автоматически записывать последовательность действий, которую вы воспроизводите как пользователь. И фактически потом, когда вы жмете с панели управления тестами воспроизвести либо конкретный тест, либо несколько тестов он начнет делать те же самые команды, которые делает пользователь. Другими словами когда вы будете делать проект на продакшн вы кроме того, что сможете утверждать, что ваш код рабочий, вы можете утверждать, что не поломалась никакая логика именно со стороны клиента

Представим себе какой-то продукт, который продается где-то там за морями. Существует первый уровень службы поддержки, которая на себя берет правильный гнев пользователя, и трансформирует этот правильный гнев в баг-отчеты и отправляет их. Все это можно заменить используя селениум ide. Т.е. если баги повторяются, то служба поддержки просто записывает сценарий с помощью селениум ide, копирует полученный код, вставляет в отчет и это уже намного больше информации, чем предоставляет стандартный отчет.

Итоги по ide: скорость входа минимальная и время входа, редактор очень простой, можно научить пользоваться кого угодно. Можно использовать не только для автоматизации тестирования.

Преимущества Selenium IDE:

· Интуитивно понятный интерфейс;

· возможность записи действия пользователя;

· с написанием тестов справится любой человек понимающий как должен работать проект;

· автоматическое генерирование *Unit кода для различных языков программирования.

Максимально простой интерфейс, который может быть. Запись действий пользователя и отдельно потом я ещё расскажу про то, что у него есть одна приятная функция как генерирование юнит-тестов под различные языки программирования.

Ложка дёгтя:

· Только для FireFox;

· после записи действия все равно нужно “допиливать ручками”;

· нет встроенного инструмента для получения XPath элементов.

Это всё таки extension к FireFox-у. Он не может гарантировать того, что ваш код будет со стороны клиента отлично работать в Хроме и любых других браузерах.

Минусы: простота. Все сценарии линейны, нельзя группировать функции и т.д. Если поменялась страница или функционал, соответственно разметка, тест скорее всего упадет, и его нужно обновлять, это не то чтобы очень просто. Работает только в firefox.

Так же если в вашем проекте очень большая бизнес логика находится на стороне фоновом, если много cron скриптов, если проект является высоконагруженным, то Selenium не целесообразен. И самый неприятный момент в использовании SeleniumIDE заключается в том, что очень часто нам нужно производить сверку каких-то элементов, значений, текстов, input-ов в связи с тем, что с клиентской стороны мы привязываемся к таким формочкам. И очень часто нам нужно находить определенную позицию элемента. В случае input-ов нам достаточно указать его name либо ID и Selenium это отлично понимает. Но очень часто нам нужно найти какую-то ссылку, дождаться диалога. И в зависимости от текста, который нам вернётся, будем утверждать, работает код, или нет. В SeleniumIDE нет инструментов для поиска XPathа каких-то элементов. Есть конечно Firebug. Его в основном и применяют для поиска этих элементов. И проблема вроде как бы не критична, но к сожалению, Selenium не дает инструменnов для того чтобы полностью в нем проводить тестирование и не прибегать к использованию каких-то сторонних инструментов.

 

Команды делятся на три типа: действия (какие-то действия), методы доступа и проверки (всевозможные проверки на странице, есть ли текст, есть ли определенный элемент, есть ли определенные атрибуты в элементе). Selenese - язык очень простой, дает немного возможностей. Только ввод последовательных команд.

Проект:

Приложение для закрытых оптовых клиентов, которые закупают определенные товары. Т.е. обычный интернет-магазин очень примитивного плана, но этому проекту очень много лет. В нем нет никакого объектно-ориентированного программирования. И было бы проще его переписать, чем покрыть его тестами. Selenium даёт инструменты, позволяющие решать эту проблему.

1ое видео демонстрирует логику авторизации пользователя.

Это видео демонстрировало то, как запускается SeleniumIDE и как происходит запись последовательности выполнения действий пользователя. Какие особенности при использовании SeleniumIDE: очень часто, когда только начинаете пользоваться, многие начинают полагаться полностью на те действия, которые записывает сама среда, и когда они ее запускают очень часто эти тесты крэшатся, и считают, что это баг SeleniumIDE. Это на самом деле баг SeleniumIDE, потому что к сожалению, данный проект еще не находится в полном релизе, он находится в бета-тестировании, и из-за этого бывают проблемы. Поэтому для всех тестов, которые вы пишите в SeleniumIDE, вы должны отлично понимать логику работы многих команд, для того, чтобы вручную потом их дозаполнять. Основные тезисы, чаще всего пропускается команды:

waitForPageToLoad (многие выполняют команду open, которая заключается в том, что открывается какая-то страница, и начинают писать какие-то команды, нажатия на ссылки, заполнение форм. И при этом когда запускаются эти тесты через SeleniumRC,они очень часто крэшатся, потому что Selenium старается их выполнять максимально быстро и не дожидается того момента, когда загрузится страница, поэтому наличие этой команды надо проверять, записал ли её Selenium, если не записана, обязательно вставлять).

также очень многие когда пишут тест последовательности действий пользователя, забывают assert и verify в этих командах. Грубо говоря,то что вы записали последовательность скриптов пользователя, если действительно какая-то формочка у вас поломалась, данный тест вам покажет, что произошла ошибка. Но совершенно не сакцентирует внимание, что возможно произошла ошибка в бизнес логике. Потому эти команды должны применяться максимально часто насколько это возможно. Желательно к тем элементам, в которых вы знаете, что должно находиться. Например, assert value вы должны быть точно уверены, что в input-е, который вы проверяете обязательно при том, когда наступила эта команда должно быть определенное значение, которое вы сверяете.

Также очень часто, можно сказать почти всегда, когда приложение вызывает popup окно, (обычный диалог) многие не дожидаются, когда оно откроется. Когда пишут это в ide, оно работает отлично, потому что в ide есть задержка, и вроде как бы тест успевает выполнять эти команды. Но на самом деле нужно всегда выполнять команду waitForPopUp. Таким образом, Selenium гарантирует то, что окошко popup появилось и дозагрузилось. Так же надо после этой команды проверять стал ли на нем фокус. Когда вы делаете это в SeleniumIDE, он делает со стороны экстеншэна фаерфокса, и он всегда точно знает, какая открылась папка. Когда вы будете выполнять это тест со стороны сервера или со стороны Selenium RC, то план может не произойти, и ваши тесты будут постоянно крэшиться из-за того, что они не нашли popup и соответственно не смогли ни найти форму, ни заполнить ее, ни сохранить.

click and clickAndWait (многие считают что после клика Selenium должен дожидаться, когда загрузится страница. На самом деле это не так, и потому когда мы будем делать клики на submit form либо любые действия, которые связаны с какой-либо отправкой и перегрузкой страницы, всегда лучше применять clickAndWait)

Видео как происходит полный процесс тестирования с использованием SeleniumIDE.

В связи с тем, что Selenium является экстеншэном к фаерфоксу, то говорить о каких-то инструментах инициализации системы сначала, не приходится. Это приходится делать вручную. Но на самом деле данный метод не является правилом, его можно применять.

Преимущества при тестирование SeleniumIDE заключается в том, что эти тесты может писать далеко не программист. Т.е. просто человек, который хотя бы понимает концепцию как работают веб приложения и что в них нужно тестировать. Поэтому очень часто, компании, у которых нет возможности набирать очень квалифицированные тест-отделы, они могут набирать более или менее технически подкованных людей для написания тестов своих проектов. И этим гарантировать для своих заказчиков максимальную работоспособность своих проектов. Очень удобно вносить изменения. Selenium просто говорит, что конкретно обрушилось, и визуально вы понимаете что случилось, и багфикс с использованием Selenium происходит достаточно быстро. К сожалению, SeleniumIDE только экстешн для фаерфокса, потому если в вашем проекте очень важна работоспобность в ie или других браузерах, то вам надо смотреть в сторону selenium rc.

___________________________________________________________________________

Собственно теперь мы закончили Selenium IDE. Теперь перейдем к Selenium Remote Controls (RC). Что это такое?

Это 3-й компонент Selenium Remote Control (RC). Он появился одним из самых последних. Но собственно он и принес Selenium самую большую популярность. Это такая надстройка, демон, который получает на вход Selenium-тест, биндится на указанный вами порт, слушает по http и принимает определенные команды и после того, как получает их, интерпретируя их через Selenium Core, начинает управлять браузером, последовательно выполняя в нем полученные команды (это может быть ввод данных формочек и любые другие тестирующие действия).

Ключевое отличие от предыдущих проектов Selenium: тесты могут быть написаны на любом высокоуровневом языке (java, c#, perl, ruby и т.д.). В этом есть и плюсы, и минусы. Плюсы состоят в том, что теперь вы можете делать все, что угодно, доступны любые прелести высокоуровневого языка, у вас есть функции, у вас есть наследование, любые структуры данных, в общем полная свобода в написании тестов. Минусы: вам нужны люди, чтобы с этим работать, которые в состоянии это делать. Супер простой тест в selenese (язык программирования Selenium IDE) разрастается в высокоуровневом языке. Т.е. мы платим сложностью за разнообразие. В итоге получаем гибкие тесты, но большие объемы кода. Инфраструктура, таким образом, становится сложнее. Отладка усложняется (когда у вас есть несколько уровней абстракций, по которым нужно то спускаться, то подниматься, отлаживать их не так просто).

Чаще всего целесообразно применять комбинацию Selenium IDE и Selenium RC, потому как в Selenium IDE все равно быстрее писать тест, покрывающий какую-то определенную логику, а Selenium RC в большинстве случаев работает с api различных других языков. Вы вполне можете писать на PhpUnit с использованием специальной реализацией PhpUnita с поддержкой Selenium, но это довольно таки долго, и опять-таки это фактически сводится к чистой интерпретации подходов PhpUnit. Для этого в Selenium IDE есть очень приятный метод. В форматах можно выбирать то, как вы хотите, чтобы Selenium трансформировал текущий список команд, на какой язык. В данном случае если выбрать php, он вам сразу создает готовый класс с готовым методом и со списком всех команд, который непосредственно можно выполнять, и в большинстве случаев он работает хорошо. Но на самом деле и этот метод становится неудобным, потому что он приводит к тому, что программист получает список html файлов, полученных с Selenium IDE, и он вынужден вручную эти тесты копировать себе в код. Это очень не удобно, и для этого в PhpUnit есть специальное решение, которое позволяет интерпретировать последовательно все файлы, реализованные в Selenium IDE, для выполнения через Selenium RC. В данном случае вам нужно создать класс, наследовать его от стандартного PhpUnit_Extensions_SeleniumTestCase, про него есть подробная документация на официальном сайте PhpUnit, и в определенной статической переменной SeleniumDirectory указать директорию, где непосредственно лежат ваши тесты, написанные в Selenium IDE. И, собственно, он будет вызываться перед выполнением каждого теста, и в нем мы указываем, в каком именно браузере мы хотим выполнять тест. Однако зачастую и этот вариант становится неудобным, т.к. иногда вам приходится разбивать тесты на определенные, так называемые, свиты, и их, к сожалению, PhpUnit не умеет интерпретировать. Он пропускает их и последовательно выполняет только те, которые находятся в папке. В чем идеологическая разница в выполнении таких тестов? Разница заключается в том, что в Selenium IDE часто прибегает к методике, что следующий тест в пределах одного свита зависит от предыдущего. В PhpUnit принято, что отдельный тест должен быть всегда максимально автономным, т.е. он не должен зависеть от того, был ли запущенен какой-то тест или не был. В случае с Selenium IDE очень часто применяется такой метод, когда один тест зависит от другого и потому выполнять их надо последовательно, как это делает Selenium IDE. Но сам PhpUnit этого не позволяет, и потому приходится делать всякие изощрения.

И все было хорошо кроме еще одного момента, который был обнаружен в PhpUnit 3.4 ну и во всех более молодых реализациях. В старых реализациях, вообще говоря, Selenium поддерживался очень косвенно (в текущих уже получше), но была очень большая проблема с командами wait. В чем принцип работы команды wait? В том, что циклически, в определенном интервале Selenium выполняется команду и ждет, пока он получит какой-то нам заведомо известный результат. Как работает PhpUnit? Когда он посылает запрос Selenium RC, он получает от него ответ: либо все хорошо, либо плохо. И уже в зависимости от этих действий, он выдает либо ошибку, либо дальше идет последовательное выполнение команд. Он в цикле зацикливает на указанное вами время, и выполняет некую команду. И в первой же неудачной итерации цикла мы не получаем желаемый результат, PhpUnit возвращает ошибку скрипт падает, соответственно закрывается браузер и тест не прошел успешно, хотя на самом деле тест должен был вполне отлично отрабатывать дальше. Эта проблема была в дальнейшем исправлена. Еще одна приятная вещь заключается в том, что Selenium RC, в отличие от Selenium IDE, умеет нормально делать скриншоты, когда произошла какая-то ошибка. Очень часто, в связи с тем, что реализация PhpUnit еще сырая, текст, который нам выдается, не всегда понятен даже программисту, уже не говоря об обывателях. А в Selenium RC реализована автоматическая генерация скриншотов. Ее очень просто использовать, вы просто должны в трех переменных указать, что вы хотите использовать генерацию, и указать, куда вы хотите производить сохранение скриншотов, и где их можно просмотреть.

В Selenium часто применяется использование firefox, но по заявлениям самой команды Selenium, она умеет работать почти со всеми браузерами. Вот список браузеров, официально заявленный, что с этими браузерами Selenium работает хорошо. На самом деле, к сожалению, дела обстоят хуже. Возможно из-за того, что проект существует уже много лет, но при этом еще ни разу в полном продакшене не был. Т.е. версия даже 1, она в продакшене фактически не побыла, и сразу появилась Selenium RC, которая находится опять-таки довольно долгий период в бета-тесте.

Так вот. Предположим, вы составили какой-то свит в Selenium IDE, и хотите, чтобы он последовательно отрабатывал не только в firefox, но и в chrome, ie, опере, safari. В PhpUnit вы просто в переменную браузера передаете массив с указанием хоста, порта и самого браузера и он будет последовательно запускать все эти тесты и в различных браузерах, будет соответственно вам писать ошибки, в каких браузерах произошли.

Ну и плюс в чём иногда недостаток применения Selenium RC. Он заключается в том, что когда у вас на проект рассчитан не такой большой бюджет и нет нормальной матчасти для различных серверов, то его применять очень тяжело. В плане работы в различных браузерах. Допустим, для того, чтобы нормально, корректно проверить код под safari, вам нужен сервер с MacOS. И за счет этого, если ваш проект действительно очень подвязан на реализации поддержки различных браузеров, вам нужно будет конкретно много серверов с различными операционными системами для выполнения этих тестов. Это очень неудобно, и тут мы постепенно переходим к следующему проекту Selenium, который решает это проблему.

Selenium Grid. Если коротко, это специальный инструмент, который занимается размыванием тестов по различным Selenium RC, чтобы гарантировать их максимальную отработку. Общая идея состоит в том, что чем больше мы будет параллельно использовать Selenium RC, тем быстрее у нас будут результаты. Selenium Grid инфраструктурно тяжелее. Если раньше был один браузер, который ходил по серверу, то в Selenium Grid ходит множество браузеров по одному сайту. Соответственно тесты должны быть написаны так, чтобы они не зависели друг от друга и работали параллельно. Проблема очевидна и с ней надо что-то делать. Хороший вариант, если тесты не зависят друг от друга. Возможное решением, если у вас тесты не могут работать параллельно, является распараллеливание сервисов, занимающихся тестированием. Selenium Grid решает проблему скорости, но на это нужно ресурсы. Хотите в 5 раз быстрее, надо в 5 раз больше ресурсов, в 100 раз быстрее, соответственно в 100 раз больше ресурсов.

В Seleniume есть ещё определенные недостатки, о которых хотелось бы упомянуть. Главный заключается в том, что если у вас в проекте есть логика, завязанная на Upload файлов, ну, допустим, если у вас какая-нибудь фотогалерея то, очень важно как происходит загрузка, произошла ли она, какие сообщения получил пользователь. Реальных нормальных решений для этой проблемы с использованием PhpUnit и Selenium IDE не существует. В связи с тем, что Selenium IDE это всё же расширение к firefox, даже не смотря на свой режим с расширенными правами, все равно не гарантирует того, что он нормально выберет файл и действительно отправит его на сервер. Все это сводится к тому, что покрывать логику связанную с uploadом файлов вам придется либо чистым PhpUnitом либо другими Unitами, которые вы используете. И ещё один неприятный момент в том, что последнее время очень часто стали применять Flash часть, опять же для таких же uploadов файлов, для отображения каких-то интерактивных действий пользователя корзины и так далее. У Selenium нет действительно нормальных решений для интерпретации этих действий во flash. Есть аналог, который можно скачать на codegoogle, называется FlashSelenium. Опять-таки, он довольно сырой. Он заключается в том, что через Javascript привязывается и совершает определенные команды. Его главный недостаток в том, что сам flash разработчик должен учитывать тот момент, что его приложение должно тестироваться в FlashSelenium. Ну, соответственно, flash-девелоперы это не очень любят.

Можно еще сказать пару слов про другие проекты Selenium. Их сейчас действительно большое количество, есть, например, Selenium on Rails, Selenium on Ruby. Первый посвящен тестирований приложений Ruby on Rails, другой посвящен использованию языка Ruby написания тестов.

Хотелось бы подытожить всё сказанное. У Selenium действительно есть ряд проблем. Но, несмотря на это, написание тестов и покрытие реальных проектов тестами с помощью Selenium занимает гораздо меньше времени. Да, их запуск не такой быстрый как в случае с PhpUnit. Если мы покрыли PhpUnit бизнес-логику, которая вам важна, эти скрипты будут отрабатываться в большинстве случаев на протяжении нескольких минут. Если же у вас довольно таки большой проект с различными формами, покрытыми тестами Selenium, эти тесты иногда будут выполняться довольно таки долго, за счёт того, что опять же применяются такие команды, как wait, которые могут каждый раз залипать на 30, на 60 секунд. Да и в целом, запуск самих браузеров очень зависит от загрузки самих серверов, на которых это происходит. И очень часто эти сервера бывают нагружены запусками других команд, других браузеров. И эти тесты прогонять получается не так часто. Но в чем глобальное преимущество использования Selenium? В том, что если ваш проект не покрывался изначально тестами, и если этот аспект довольно-таки критичен, вы это можете сделать малой ценой, как времени, так и денег компании, самого проекта. При этом вы сможете гарантировать, что и ваша бизнес-логика отлично работает, и плюс к этому вы сможете гарантировать, что работает и клиентская часть. Потому, применять Selenium в связке с PhpUnit либо JUnit всегда отличная практика.

Несколько советов для тех, кто выбирает этот инструмент. Не спишите с запуском всех проектов Selenium, пользуйтесь Selenium IDE, все прекрасно работает. Поймите разницу между инструментами. Если инструмент может дать больше чем нужно, то должен прозвенеть звоночек, а нужен ли он. Потому как любые возможности придется платить ресурсами, скоростью, тяжеловесностью или еще чем. Лучше всего конечно проконсультироваться у людей, которые уже сделали нечто подобное.

 

 


Дата добавления: 2015-11-05; просмотров: 25 | Нарушение авторских прав




<== предыдущая лекция | следующая лекция ==>
Securities market. Questions to monitor student’s academic achievement | Геометрический анализ плоских рычажных механизмов

mybiblioteka.su - 2015-2024 год. (0.015 сек.)