Перейти к содержимому

Публикации owasp

29 публикаций создано owasp (учитываются публикации только с 20 апреля 2023)



#125738 Взаимодействие отделов тестирования и разработки

Отправлено автор: owasp 10 января 2014 - 22:10 в QA: обеспечение качества

Много ответов, понял характер советов, большое спасибо. Давайте закроем обсуждение.
Важная ремарка про компанию: разработчики, документаторы, тестировщики, администраторы, аналитики и поддержка выкладываются ради друг друга по полной. Роли совмещаются, так как люди с вагонами знаний и опыта. Компания небольшая, правила в ней меняются часто, в лучшую сторону, и уже сменились. Зарплаты достойные, премия не играет роли (моё скромное мнение). Вероятно, такого нет больше нигде.
Любые показатели не прошедшие проверку не влияют на премию, но сохраняются и их считать надо (считал бесполезным лишь этот момент).

С момента начала обсуждения эксперимент с оценкой друг друга прошел и забыт. Вывод - можете попробовать сделать взаимную оценку участников команды, польза будет в том, что произойдёт некое изменение ("любая движуха, кроме голодовки" (с) на пользу), которое можно будет заменить чем-то другим, улучшив мир.

И текущий сайт не нравится (личная оценка). Повторюсь, давайте закроем обсуждение.



#117486 Тестирование безопасности сайтов. Простветите невежду.

Отправлено автор: owasp 27 апреля 2013 - 18:06 в Тестирование защищенности

Обратите внимание на текущий сайт.
upd.
Текст основан на материале статьи "Площадка для взлома: головоломки для хакеров" (http://www.xakep.ru/...289/default.asp). Отличается структурой и ссылками.
Уязвимые web-приложения
____________________________________________________
Damn Vulnerable Web App
SQL-инъекции, XSS и многое другое.
Это специальная разработка для обучения и тестирования, а не реальное web-приложение.

GNU GPL v3 (1,3 Мб)

Contact: dvwa@dvwa.co.uk
Website: http://www.dvwa.co.uk
Download: http://sourceforge.net/projects/dvwa/
SVN: http://dvwa.svn.sour...et/svnroot/dvwa
PHP, MySQL
____________________________________________________

Moth​
SQL-инъекции, XSS и многое другое. Реальные приложения (старыми WordPress, Vanilla, ...) и демонстрационные приложения с уязвимостями. Данный проект - тестоавя площадка для w3af (Web Application Attack and Audit Framework, http://w3af.sf.net/).
GNU GPL (416,3 Мб )

WebSite: http://www.bonsai-se...search/moth.php
Download: http://sourceforge.n...3af/files/moth/
VMware (Ubuntu 8.10)​, PHP, Tomcat 6, MySQL
____________________________________________________

OWASP WebGoat
XSS, контроль доступа, безопасность потоков, монипуляция скрытыми полями форм, манипуляция параметрами, утечка сессионных cookies, слепые SQL-инъекции, числовые SQL-инъекции, строковые SQL-инъекции, веб-сервисы, ошибки аутентификации, опасные HTML комментарии, ...
GNU GPL v2 (83 Мб)

Website: https://www.owasp.or...WebGoat_Project
Devel: http://code.google.com/p/webgoat/
Download: http://code.google.c.../downloads/list
Video: http://yehg.net/lab/...ing/webgoat.php
Tomcat, Java, J2EE
____________________________________________________
Butterfly​
Наличие уязвимостей: уязвимости сессий, инъекции данных, ошибки загрузки файлов, межпользовательский доступ, повышение привелегий, удалённое выполнение кода, AJAX уязвимости.
Руководство по устранению ​этих уязвимостей.

(23 Мб, 21.10.2008)

Website: http://sf.net/projec...hebutterflytmp/
Linux, FreeBSD, Apache, PHP, MySQL
____________________________________________________
Securebench​
Подборка из 8-ми реально существующих программ, написанных на Java, используются старые версии: jboard (0.30), blueblog (1.0), webgoat (0.9), blojsom (1.9.6), personalblog (1.2.6), snipsnap (1.0-BETA-1), road2hibernate (2.1.4), pebble (1.6-beta1), roller (0.9.9).
Наличие уязвимостей: SQL-инъекции, XSS, HTTP-склейка, раскрытие путей (Path traversal) и, возможно, ​многие другие.

(105 Мб)

Website: http://suif.stanford...its/securibench
Java, J2EE
____________________________________________________
Mutillidae​
Приложение на PHP, в котором есть все уязвимости OWASP Top 10.
(4,8 Мб)

Website: http://www.irongeek....hp-owasp-top-10
PHP, Apache, MySQL
____________________________________________________
OWASP InsecureWebApp
Apache License v2.0​ (0,7 Мб, 27.01.2005)

Website: https://www.owasp.or...eb_App_Project​
Download: http://sourceforge.n...insecurewebapp/
Java, Tomcat
____________________________________________________

Многие фирмы, выпускающие инструменты автоматичкого поиска уязвимостей веб-приложений серьезно подходят к процессу тестирования этих сканеров. Для тестирования сканеров созданы специальные уязвимые узлы (тестовые площадки), эти площадки наглядно демонстрируют возможности сканера. Если хочется узнать, что говорит определённый сканер, если находит SQL-инъекцию. Или узнать - какие SQL-инъекции сканер находит, а какие нет. То можно использовать эти тестовые площадки.
Эти сайт заточены именно под сканеры, уязвимости на них фиктивные, а не настоящие.

Адрес:​​​​​ http://zero.webappsecurity.com/
Платформа:​​​​​ ASP​
Сканер разработчика​​:​​​​​ HP WebInspect​

Адрес:​​​​ ​ http://demo.testfire.net/
Платформа:​​​​ ASP.NET
Сканер разработчика:​​​​​​ IBM Rational AppScan

Адрес:​ http://testaspnet.vulnweb.com/
Платформа:​ ASP.NET
Сканер разработчика: Acunetix Web Vulnerability Scanner

Адрес:​​ ​ http://testphp.vulnweb.com/
Платформа:​​ PHP
Сканер разработчика:​​ Acunetix Web Vulnerability Scanner

Адрес:​​​ ​ http://testasp.vulnweb.com/
Платформа:​​​ ASP
Сканер разработчика:​​​​​ Acunetix Web Vulnerability Scanner



#117252 Не могу запустить ни один тест!

Отправлено автор: owasp 18 апреля 2013 - 09:07 в Selenium - Functional Testing

Столкнулся с такой же ошибкой.
WebDriver 2.32.0, Firefox 19.0, 20.0, 20.0.1.

SetUp : OpenQA.Selenium.WebDriverException : Failed to start up socket within 45000 ms

Со стеком:
at OpenQA.Selenium.Firefox.Internal.ExtensionConnection.ConnectToBrowser(TimeSpan timeToWait) in c:\Projects\WebDriver\trunk\dotnet\src\WebDriver\Firefox\Internal\ExtensionConnection.cs:line 266
at OpenQA.Selenium.Firefox.Internal.ExtensionConnection.Start() in c:\Projects\WebDriver\trunk\dotnet\src\WebDriver\Firefox\Internal\ExtensionConnection.cs:line 98
at OpenQA.Selenium.Firefox.FirefoxDriver.StartClient() in c:\Projects\WebDriver\trunk\dotnet\src\WebDriver\Firefox\FirefoxDriver.cs:line 225
at OpenQA.Selenium.Remote.RemoteWebDriver..ctor(ICommandExecutor commandExecutor, ICapabilities desiredCapabilities) in c:\Projects\WebDriver\trunk\dotnet\src\WebDriver\Remote\RemoteWebDriver.cs:line 88
at OpenQA.Selenium.Firefox.FirefoxDriver..ctor(FirefoxBinary binary, FirefoxProfile profile, TimeSpan commandTimeout) in c:\Projects\WebDriver\trunk\dotnet\src\WebDriver\Firefox\FirefoxDriver.cs:line 162
...
Никак не исправляется. Возникает на серверной ОС.
Наблюдается только на одной машине с Windows Server 2008.
На Windows 7 всё как надо работает.

Дополнительно к ней есть проблема - расширение WebDriver загружается как отключенное.
В резульатете при старте браузера настройки не применяются и браузер ведёт себя как при первом запуске.
Эта дополнительная проблема описана на StackOverflow: http://stackoverflow...n-browser-start
Как побороть отключенность плагина после загрузки - нашел.
В тесте использовал установлку следующей настройки:
firefoxProfile.SetPreference("browser.download.dir", System.Environment.CurrentDirectory);
Если её использовать, то после старта - расширения браузера не включаются. Если её не использовать, то расширение загружается корректно.
Таким образом, некоторые пользовательскиенастройки могут помешать работе.

Но основная проблема - Failed to start up socket within 45000 ms, пока не решилась.
В похожих темах решения пока тоже не нашел: https://groups.google.com/forum/?fromgroups#!search/Failed$20to$20start$20up$20socket$20within
Пробовал использовать решения:
1. Увеличить время ожидания (сделать больше 45 секунд)
FirefoxBinary firefoxBin = new FirefoxBinary("C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe");
firefoxBin.Timeout = TimeSpan.FromSeconds(120.0);
2. Переустановить Firefox, почистить профили.
3. Сменить порт
var firefoxProfile = new FirefoxProfile();
firefoxProfile.Port = 40000;
4. Обновить WebDriver (и так последняя версия)
5. Перезагрузить виртуалку.
...

update:
Решил проблему. Но не локализовал решение, сказать что именно сыграло решающую роль - сложно.



#117134 Как ведет себя moveToElement

Отправлено автор: owasp 15 апреля 2013 - 18:00 в Selenium - Functional Testing

Если использовать xpath с абсолютными путями, то могут появиться ложные срабатывания?

Нет ложных срабатываний не будет. Просто появляется дублирование кода - для всплывающего элемента нужно повторять в селекторе селектор родительского элемента (так как обычно, у всплывающих элементов нет своего уникального идентификатора в рамках всей страницы). Если не считате дублирование текста селекторов важным, то никаких проблем нет.

При изменении дизайна, придётся не один раз изменить селектор для основного элемента, а изменить его несколько раз - дополнительно поправив селекторы дочерних элементов.

В моём проекте есть строки таблицы (которые могу уникально определить), а внутри строк есть всплывающие элементы - кнопки действий, что появляются для каждой строки при наведении. И у кнопок своих уникальных селекторов нет.
Единственный вариант уникального селектора для всплывающего элемента, заданный относительно браузера - "Уникальный селектор основной строки" + "селектор всплывающего элемента".
Но можно, ведь, получить основную строку по селектору "Уникальный селектор основной строки", а уже относительно полученного IWebElement получить дочерние элементы по коротким относительным селекторам "селектор всплывающего элемента".

Если использовать Java и базовый паттерн PageObject, то задавать относительные селекторы в атрибутах нельзя - все селекторы задаются относительно браузера => приходится дублировать селекторы.
Если использовать чистый PageObject, то работу со всплывающими элементами без дублирования селекторов можно организовать передавая в методы работы с ними базовый для них IWebElement (а относительно него искать).

Можно использовать паттерн HTML Elements, который реализован в разработке Яндекса, тогда исключается дублирование кода и дублирование селекторов:
http://habrahabr.ru/...ex/blog/158787/
https://github.com/y...ls/htmlelements

В своих тестах использую C#. Идеи HTML Elements повторил, как сумел, средствами dotNet. Получилось сыровато (есть проблема, когда компонент вложен в компонент, вложен в компонент и все эти элементы не являются кешируемыми - конечные узлы ищутся долго), но работает. Думаю сделать механизм обновления дерева компонент (Refresh()), как это сделано в TestComplete и разрешить каждому компоненту кешировать экземпляр своего родительского компонента. Это немного увеличит затраты по памяти (16 байт на ссылку), но увеличит быстродействие.



#117049 Как ведет себя moveToElement

Отправлено автор: owasp 12 апреля 2013 - 19:08 в Selenium - Functional Testing

1) Указатель оказывается в том месте, куда он был помещён. На своё реальное место указатель не возвращается.
2) Имеет значение. Чтобы навести указатель на элемент, который может быть в конце страницы (быть не видимым) можно пробовать отображать его, используя скроллинг.
Например, в C# это делается при получении значения свойства LocationOnScreenOnceScrolledIntoView см. http://selenium.goog...ledIntoView.htm
var fakePoint = (iwebElement as Locatable).LocationOnScreenOnceScrolledIntoView;
var fakePoint = (iwebElement as RemoteWebElement).LocationOnScreenOnceScrolledIntoView;
В Java есть аналогичный get-метод
getLocationOnScreenOnceScrolledIntoView()
, см. http://selenium.goog...rolledIntoView()
3) Особо с hover-элементами не работал, но понятно, что при работе с ними можно:
3.1. использовать поиск относительно базового элемента, на котором сейчас фокус, а не относительно страницы браузера. Так как поиск относительно браузера даст ложные срабатыввания (если не фильтровать по видимости) и будет выполняться дольше.
3.2. не использовать кеширование элементов (каждый раз искать элементы по новой), так как наличие hover-элемента на странице непостоянное.



#116722 Параллелизация или как сэономить ресурсы?

Отправлено автор: owasp 08 апреля 2013 - 20:57 в Selenium - Functional Testing

Для вкладок нельзя указать свой proxy. Proxy задаётся один на весь браузер. Кроме того, одновременно можно работать только с одной вкладкой браузера перед началом работы с другой вкладкой, нужно переключиться на неё. Таким образом, в рамках одного браузера нельзя сделать параллельное тестирование. Нужно запускать несколько тестов сразу (каждый тест будет открывать свой браузер).
Одновременно запустить множество Selenium возможно. Про "Параллельный Selenium" частично описано в статье "Тестирование в Mail.Ru Group": http://habrahabr.ru/...ru/blog/165877/
Цитата из статьи:

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

Мы решили проблемы параллельной работы тестов на одной ноде, внеся исправления в Java и C++ код самого Selenium. Мы добавили блокировки на выполнение однопоточных действий, переключение фокуса окна перед теми действиями, которым оно необходимо. Также мы почининили многопоточность upload’а файлов в IE, и добавили эту функцию для Opera. На момент написания статьи все эти исправления работают с версией Selenium 2.26.

Предвосхищая возможный вопрос, хочу сказать, что мы очень хотим, чтобы наши исправления стали частью официального Selenium. Мы выкладывали наши патчи на github (например, в https://github.com/wladich/operadriver) и пересылали их разработчикам. Однако, в силу различных причин, ни один из патчей в полной мере пока еще не стал частью Selenium, хотя мы видим часть наших строк в коде последних версий Selenium. Самая свежая порция наших исправлений пока еще не открывалась, и мы будем рады, если у разработчиков Selenium есть интерес к ней.


Selenium.WebDriver для Firefox во многом зависит от своей C++ реализации firefox.dll (кстати, многие считают, что Selenium написан на Java, прямо, только на Java, и в Wikipedia также написано - а это не так). И раз сказано, что Mail.ru патчили C++, то и работа с Firefox, вероятно, не идеальна, с точки зрения многопоточности.



#116719 Сделать окно активным (Selenium Webdriver)

Отправлено автор: owasp 08 апреля 2013 - 20:43 в Selenium - Functional Testing

В своих тестах при закрытии поледнего открытого окна возвращаюсь на последний элемент списка окон.
В примете кода, приведённого выше:
String handle = webDriver.getWindowHandle();
webDriver.switchTo().window(handle);
В первой строке, получаю не текущее окно, а весь список окон (их ведь может быть несколько):
handleList = webDriver.getWindowHandles();
Проверяю, что список непуст. Получаю последний элемент списка. Переключаюсь на последний элемент списка.
В C# это делается с помощью Linq, последняя строка получается методом Last().



#116717 WebDriver работа с выпадающим меню

Отправлено автор: owasp 08 апреля 2013 - 20:26 в Selenium - Functional Testing

Да, дело в траектории движения мыши.
moveToElement передвигает указатель от ценра элемента "Ходожественные фильмы" к центру элемента "Короткометражный ходожественный фильм". На рис. 3 видно, что прямая соединяющая центры этих элементов проходит через "Документальные фильмы".

Сложность тестирования, вероятно, связана с некорректной реализацией иерархического меню. Ваше меню не использует эффект запаздывания (setTimeout в javascript), либо запаздывание слишком мало.

Используйте в реализации меню эффект запаздывания, или более удобно организуйте работу с выбором элементов следующего уровня (как в Amazone).
Для сравнения меню с запаздыванием и меню без запаздывания (но при этом рабочего, более удобного) можете обратиться к статье Загадка выпадающего списка «Амазона»: http://habrahabr.ru/post/171905/

Или в тесте нужно передвигать указатель не по прямой соединяющей центры пунктов, а по кривой, не задевающей другие элементы (но пользователи не будут так делать, и сложный дизайн не будет пользоваться популярностью).
Кривая следующая (вправо по горизонтали и, возможно, вниз по вертикали):
moveToElement(пункт меню)
moveToElement(первый пункт подменю)
moveToElement(нужный пункт подменю)
click(нужный пункт подменю)



#116602 Chrome, запускаемый через chromedriver.exe НЕ восстанавливает настройк

Отправлено автор: owasp 05 апреля 2013 - 16:38 в Selenium - Functional Testing

У класса ChromeOptions есть методы добавления ключей запуска.
public void AddArgument(string argument)
public void AddArguments(params string[] arguments)
public void AddArguments(IEnumerable<string> arguments)

Наверно, они и предназначены для данной задачи.
Для запуска можно использовать:
public ChromeDriver(ChromeOptions options)
сработает, если chromedriver.exe будет находиться в текущей папке теста.
Если chrome-driver где-то в другом месте, то есть метод
public ChromeDriver(string chromeDriverDirectory, ChromeOptions options)

То есть, сначала создать объект
ChromeOptions
(вместо DesiredCapabilities).
Используя,
AddArgument
задать параметры.
Потом передать созданный ChromeOptions в качестве параметра в
ChromeDriver(ChromeOptions options)
.
Методы смотрел в исходниках:
https://code.google....eOptions.cs#113
https://code.google....omeDriver.cs#76
(написаное выше написано для WebDriver dotNet, но думаю состав классов примерно одинаков везде)



#116601 WebDriver и SSL Untrusted certificate

Отправлено автор: owasp 05 апреля 2013 - 16:20 в Selenium - Functional Testing

Никак. Отключать в настройках браузера проверку корректности SSL.
Например, при запуске Firefox через WebDriver так делается:
См. https://code.google....xProfile.cs#438
AddDefaultPreference(prefs, "security.warn_entering_weak", "false");
            AddDefaultPreference(prefs, "security.warn_entering_weak.show_once", "false");
Соотвественно, если вам нужно с помощью Selenium что-то проверять, и при этом критично наличие SSL/TSL, то настройки безопасности нужно программно вернуть в безопасные значения (так как по-умолчанию они понижаются), но это - ситуация обратная вашей.

В Chrome параметры можно переопределить при загрузке, задав их как ключи командной строки.
http://peter.sh/expe...tificate-errors
Далее нужно при старте переопределить путь к исполняемому файлу, включить в путь нужные параметры командной строки. Как это сделать - не знаю. См. http://software-test...p?/topic/25570/

В Internet Explorer расширенные парамерты задаются навсегда (временно их поменять нельзя). Меняются до начала тестирования, вручную. Поэтому не рекомендую понижать настройки безопасности в IE. После смены настроек, факт изменения забудется и в результате - машина с неверно сконфигурированным SSL/TSL в IE.



#116356 Selenium IDE не работает с всплывающим окном

Отправлено автор: owasp 27 марта 2013 - 19:07 в Selenium - Functional Testing

Думаю селекторы у вас неправильные. Вот элемент и не находится. Или вы обращаетесь к элементу, не дожидаясь его появления.
Вероятно, у всплывающего окна есть более точные селекторы, класс или ид, а не просто div[6]. Советую использовать css-селекторы. И сделать ожидание появления элемента (диалога) с нужным селектором.

А указанная вами статья депрессивная, если ей следовать, то использование Selenium - пустая трата времени. А это не так. Если бы автору статьи задачу поставили так: есть пара недель, автоматизируй тестирование вот этого сложного сайта и напиши нормальный код, так как потом его надо будет передать коллегам, которые Selenium никогда не видели; прототип нужен через неделю. То у него бы всё получилось (так как права на ошибку не было бы).



#116222 ошибка: Element is not currently visible

Отправлено автор: owasp 25 марта 2013 - 12:06 в Selenium - Functional Testing

Здравствуйте, если посмотрите в исходники Selenium.WebDriver, то там видно, что перед каждым Click() происходит MouseMove на элемент, по которому будет выполняться щелчок. Таким образом, если при смене фокуса кнопка пропадает, то она пропадает и кликнуть по ней нельзя - это нормально (браузер ведёт себя правильно, а тестируемое приложение должно стать более пригодно к тестированию). По этой причине неуверен, что даже руками (не автотестом) удостаться повторить клик по кнопке, которая доступна только когда курсор наведён на другую кнопку.

Но всё же, программно кликнуть по кнопке, не наводя на неё указатель мыши, можно. Если используете dotnet, то смотрите исходный код файла, где выполняется Click():
https://code.google..../ClickAction.cs
    /// <summary>
    /// Defines an action for clicking on an element.
    /// </summary>
    internal class ClickAction : MouseAction, IAction
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ClickAction"/> class.
        /// </summary>
        /// <param name="mouse">The <see cref="IMouse"/> with which the action will be performed.</param>
        /// <param name="actionTarget">An <see cref="ILocatable"/> describing an element at which to perform the action.</param>
        public ClickAction(IMouse mouse, ILocatable actionTarget)
            : base(mouse, actionTarget)
        {
        }

        #region IAction Members
        /// <summary>
        /// Performs this action.
        /// </summary>
        public void Perform()
        {
            this.MoveToLocation();
            this.Mouse.Click(this.ActionLocation);
        }

        #endregion
    }
Тут видно, что перед щелчком на элемент наводистя указатель мыши.
Значит, если хотите сделать второй клик чистым кликом без наведения курсора мыши на место клика (так-то, считаю это нетестовым случаем), то выполняете не
IWebElement.Click()
, где IWebElement - ваш элемент
а выполняйте
RemoteWebDriver.Mouse.Click(IWebElement)
, где RemoteWebDriver - браузер, а IWebElement - элемент по которому нужно кликнуть.

Также, возможно вам поможет использование нативных событий. *NativeEvents = true - параметр различных браузеров. Возможно, нативные события дадут нужную задержку и корректное поведение. Говорю вот о чём:
            var firefoxProfile = new FirefoxProfile();
            ...
            //Включение режима генерации JavaScript событий (а не имитации их вызова)
            firefoxProfile.EnableNativeEvents = true;
            //Создание драйвера с настройками из профиля
            var browser = new FirefoxDriver(firefoxProfile);



#116123 Element not found in the cache

Отправлено автор: owasp 21 марта 2013 - 13:36 в Selenium - Functional Testing

А какие импорты вы используете? у меня куски типа TagName, Text catch (Exception) упорно подсвечиваются красным в эклипсе...

А вообще как-то странно, почему в одном тесте например вебдрайвер по линке 2 раза кликает, а на третий раз или "Element is not currently visible and so may not be interacted with" или "Element not found in the cache - perhaps the page has changed since it was looked up"

В java соотвествующие поля есть, они с маленькой буквы пишутся. А приведённый мною код на C# (using OpenQA.Selenium.WebDriver).
Практика показала, что дёрганье элементов не особо помогает (когда память заканчивается, а браузеры её потребляют быстро, то ошибки всё равно появляются), больше помогает добавление оперативной памяти виртулке, где тесты выполняются.



#115847 переход на WebDriver

Отправлено автор: owasp 17 марта 2013 - 06:29 в Selenium - Functional Testing

Всем,Привет)
Хотелось бы обратиться с вопросом.
Не могу добиться стабильности работы ожидания. Использую C# и webdriver.
Нарушается последовательность кликов.

По теме получения коллекции элементов:
Для списочных однотипных элементов (например, содержимое каталога) использую получение списка (FindElements вернёт ReadOnlyCollection<IWebElement>), сортировку или фильтрацию элементов с помощью Linq (OrderBy, Where). Например, в результате запроса было возвращено 1000 ссылок. Все они есть на странице, но 50 из них отображены, а остальные скрыты (просто уже подгрузились ajax-ом). Таким образом нам нужно получить только те элементы из результата запроса, что видимы. И, допустим, нет доверия к порядку выдачи элементов на страницу, поэтому самостоятельно сортируем список элементов по значению атрибута id.
Псевдокод (в целом, псевдокод не совсем корректный, так как после FindElements и Where нужно проверять, что в коллекции есть хоть один элемент, иначе будет исключение (работа с пустым списком)):
var collectionLinks = Browser.FindElements(By.CssSelector(".list_item")).Where(webElement => (webElement.Displayed == true)).OrderBy(webElement => webElement.GetAttribute("id"));
foreach(var link in collectionLinks)
{
    link.Click();
    //...обработчик реакции на щелчок по ссылке
    btn1.Click();
    //...обработчик реакции на щелчок по кнопке
}

На псевдокоде всё красиво. В реальности элементы вытесняются из dom-модели (при щелчке по элементам (ссылке и кнопке), dom-модель перестраивается, и в результате ссылки на IWebElement, что хранятся в коллекции collectionLinks со временем становятся неактуальными - WebDriver скажет, что элемента нет в кеше).
Даже получение статуса видимости и получение атрибута id может создать ажиотаж работы с dom-моделью (если список большой, то обращений получится много), в результате ажиотажа с большим количеством элементов, другая часть элементов (в силу их относительной неиспользуемости) устареет. Это гипотеза, почему на самом деле так происходит не знаю (возможно, причина в самом тестируемом сайте: на сайте, что тестирую, огромное количество обработчиков на каждое событие - любое действие, любой клик, вызывают реакцию разнородного javascript-кода, который, работая асинхронно и запускаясь по таймеру, сам может в любое время создавать и менять элементы страницы, понижая удобство тестирования).
И к моменту завершения операции фильтрации и сортировки:
var collectionLinks = Browser.FindElements(By.CssSelector(".list_item")) //Получение коллекции
    .Where(webElement => (webElement.Displayed == true)) //Фильтрация
    .OrderBy(webElement => webElement.GetAttribute("id")); //Сортировка
коллекция уже может содержать устаревшие ссылки (если элементов было очень много).
И поэтому приходится отказываться от работы с большими коллекциями элементов, работая с одиночными элементами или малыми коллекциями.

По теме ожидания:
Базовый Explicit Wait и Implicit Wait у меня не работают. Поэтому использовал дополнительный поисковый механизм. На основу был взят способ из фреймворка TestStack.Seleno, где все операции по поиску элементов сосредоточены в объекте Finder, который возвращается по вызову метода Find() (объект и метод - часть TestStack.Seleno, их нет в Selenium.WebDriver).
На псевдокоде, например, поиск одиночного элемента выглядит так:
var stopWaitTime = DateTime.Now.AddSeconds(paramMaxWaitTime);
IWebElement result = null;
do
{
    result = ... тут поиск элемента по нужным критериям
}
wail((result == null) && (DateTime.Now <= stopWaitTime))
return result;
В TestStack.Seleno поиск выглядит так:
https://github.com/T...lementFinder.cs
а конкретно ожидание элемента использует базовый wait и сделано как метод расширения ElementWithWait (но у меня оно не работало):
https://github.com/T...erExtensions.cs

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



#115620 [testlink] Тестирование одинаковых тестов на разных версиях продукта о

Отправлено автор: owasp 12 марта 2013 - 06:21 в Управление тестированием

Выглядит так. Создан каталог тестов "ЭТ" (экспресс-тесты). В нём общие быстрые тесты, которые надо выполнять каждый раз. Считается, что эти тесты никогда не устаревают. И каждый раз эти тесты включаются в состав выполняемых тестов.

Тесты не из каталога ЭТ пишутся под конкретные текущую задачу, и устаревают со временем. Некоторые из них переходят в состав "ЭТ".



#115597 Как собрать Selenium.Webdriver (dotnet) из исходников

Отправлено автор: owasp 11 марта 2013 - 13:35 в Selenium - Functional Testing

Есть ли те, кто может рассказать как собирается из исходных кодов Selenium.Webdriver?
При сборке нужен файл "mozilla-config.h" для проектов:
  • IEDriverServer
  • webdriver-firefox
  • webdriver-firefox-esr-latest
  • webdriver-firefox-esr-previos
  • webdriver-firefox-latest
  • webdriver-firefox-previos
  • webdriver-firefox

Какой файл нужен, первый попавшийся из поисковика? Например, http://code.google.c...onfig.h?r=10393

Также после запуска тестов для Firefox нужен xpi-файл (webdriver.xpi - расширение для Firefox). В собранном файле WebDriver.dll файл webdriver.xpi есть как ресурс (см, например, selenium-dotnet-2.31.2.zip на https://code.google..../downloads/list ). В проекте не понял, как webdriver.xpi попадает в ресурсы WebDriver.dll.



#115469 Тестирование верстки с помощью Selenium

Отправлено автор: owasp 06 марта 2013 - 14:31 в Selenium - Functional Testing

В данный момент просто сохраняю в лог (пока тестовый) ссылки на скриншоты всех страниц, а также размеры и координаты всех важных элементов.
Код метода, которым получаю размеры и положение важных элементов отражен в комментарии: http://software-test...post__p__115467 (6-й комментарий).
На данном этапе разработки тестов мне сказали не заниматься вёрсткой. Поэтому, просто коплю статистику. Потом планирую сравнивать положение и размер ключевых элементов от запуска к запуску. И если вёрстка поедет, то это будет видно по положению элементов.



#115467 Element not found in the cache

Отправлено автор: owasp 06 марта 2013 - 14:13 в Selenium - Functional Testing

У меня похожаю ошибка, но выскакивает она как-то рандомно только в двух тестах и в основном в фаерфоксе. Локально у меня всегда проходит,а валится на серваке. Не знаю как ее отловить.
Кликаю не так как вы говорили, а сначала нахожу элемент,а потом уже кликаю. Иногда проходит иногда нет.

Также случается:
Для FireFox:
OpenQA.Selenium.StaleElementReferenceException : Element not found in the cache - perhaps the page has changed since it was looked up
Для Internet Explorer:
OpenQA.Selenium.StaleElementReferenceException : Element is no longer valid
Чтобы проблемные элементы оставалися актуальными, стал перед обращением к ним получать информацию о них, в частности атрибуты. Указанных выше исключений не стало.

Для этого использую метод расширения Info() для IWebElement (он так-то для получения информации об элементе, для записи в лог, но он получает атрибуты элемента, тем самым не давая браузеру викинуть элемент из кеша):
    //C# для Selenium.Webdriver.dotNet40
    public static class WebElementExtension
    {
        public static string Info(this IWebElement element)
        {
            string info = "{";
            try { info += String.Format("Type: {0}; ",          element.GetType().Name); } catch (Exception) { };
            try { info += String.Format("Tag: {0}; ",           element.TagName); } catch (Exception) { };
            try { info += String.Format("class: {0}; ",         element.GetAttribute("class")); } catch (Exception) { };
            try { info += String.Format("id: {0}; ",            element.GetAttribute("id")); } catch (Exception) { };
            try { info += String.Format("Text: {0}; ",          element.Text); } catch (Exception) { };
            try { info += String.Format("Displayed: {0}; ",     element.Displayed); } catch (Exception) { };
            try { info += String.Format("Location: {0}:{1}; ",  element.Location.X, element.Location.Y); } catch (Exception) { };
            try { info += String.Format("Size: {0}x{1}; ",      element.Size.Width, element.Size.Height); } catch (Exception) { };
            info += "}";
            return info;
        }
    }

Таким образом, если раньше некий код приводил к исключениям, связанных с кешированием, (код вида):
btnClose.Click();
То обращение к атрибутам элемента перед кликом по нему, решает проблему, инициализирцет элемент, перед кликом по нему:
btnClose.Info();
btnClose.Click();



#115420 [testlink] Тестирование одинаковых тестов на разных версиях продукта о

Отправлено автор: owasp 05 марта 2013 - 15:07 в Управление тестированием

В Testlink есть поле "Версия для назначения". Когда вы переходите к назначению отвественных за выполнение тестов открывается страница "Назначение ответственных за выполнение тестов" (или "Execution assignment"). Где в разделе "Настройки" (слева вверху) второе поле - "Версия для назначения".

Добавление новой версии к продукту:
  • Перейти на стартовую страницу
  • В правом верхнем углу есть группа из четырёх ссылок (у меня такая локализация):
    • Управление тест-планами
    • Управление версиями
    • Управление правами доступа
    • Управление этапами
  • Кликнуть по ссылке "Управление версиями" (<http://testlink>/lib...n/buildView.php)
  • Добавить описание тестируемых версий (после этого можно будет назначить исполнителя тестов на определённой версии)



#115395 помогите с автотестом на C# Visual Studio 2010

Отправлено автор: owasp 04 марта 2013 - 18:54 в Начинающему тестировщику

SeleniumWebDriver это такая удобная обёртка над вызовом javascript функций для различных браузеров. За счёт того, что все браузеры более-менее одинаково работают с javascript, интерфейс получается единым. Все Click(), Select(), ... в конечном счёте приводят к выполнению javascript. Естественно, есть возможность выполнения произвольного javascript-кода. Метод ExecuteScript.
//webDriver - экземпляр RemoteWebDriver, который реализует IWebDriver, много чего ещё и IJavaScriptExecutor, ниже вызывается метод IJavaScriptExecutor.ExecuteScript
var jsExecuteResult = webDriver.ExecuteScript("return 1+1;");
int intResult = Convert.ToInt(jsExecuteResult);



#115392 Selenium 2.0 - как снять скриншот

Отправлено автор: owasp 04 марта 2013 - 16:44 в Selenium - Functional Testing

В какой-то момент стало нехватать возможности получить снимок всех экранов (а не только содержимого текущего окна браузера).
Тут мне помог код из проекта, который нашел на хабре:
см. https://bitbucket.or...rGn/screenpaste
ScreenPaste / ScreenPaste / Screenshot.cs

Адаптировал этот код в свой проект (встроил cнятие снимка текущей страницы и снимков всех экранов при каждом возникновении исключения).
В коде ниже, метод TakeScreenShot работает также как написано в комментариях выше.
А метод TakeAllScreen работает на основе кода из проекта, указанного по ссылке на bitbucket:

public class SeleniumHelperException : Exception
    {
        protected static List<string> TakeScreenShots()
        {
            List<string> listPathes = new List<string>();
            if (SeleniumRunner.Host != null)
            {
                ICamera camera = SeleniumRunner.Host.Camera;
                listPathes = camera.TakeAllScreen();
            }
            return listPathes;
        }

        protected static string TakeScreenShotCurrentPage()
        {
            if (SeleniumRunner.Host != null)
            {
                ICamera camera = SeleniumRunner.Host.Camera;
                return camera.TakeScreenshot();
            }
            else
            {
                return null;
            }
        }

        protected static string AddScreenShotPathToMessage(string message = null)
        {
            string messageWithScreenShot = message;
            string screenShotPath = TakeScreenShotCurrentPage();
            if (screenShotPath != null)
            {
                if (message != null)
                {
                    messageWithScreenShot = String.Format("{0}. ScreenShots: [{1}]", message, screenShotPath);
                }
                else
                {
                    messageWithScreenShot = String.Format("ScreenShots : [{0}]", screenShotPath);
                }

                foreach (String path in TakeScreenShots())
                {
                    messageWithScreenShot += String.Format(", [{0}]", path);
                }
            }
            return messageWithScreenShot;
        }

        public SeleniumHelperException()
            : base(AddScreenShotPathToMessage())
        {
        }

        public SeleniumHelperException(string message)
            : base(AddScreenShotPathToMessage(message))
        {
        }

        public SeleniumHelperException(string message, Exception innerException)
            : base(AddScreenShotPathToMessage(message), innerException)
        {
        }
    }



#115391 Открытие новой вкладки в IE8

Отправлено автор: owasp 04 марта 2013 - 16:31 в Selenium - Functional Testing

Как бы не накликать. Но у меня работает переключение в новое окно и возврат назад тоже работает. Не работало сначала, когда настраивал опции, при старте браузера.
Потом опции настраивать не стал (не стал вообще использовать InternetExplorerOptions):
            var browser = new InternetExplorerDriver();
            browser.SetImplicitTimeout(5);
            TryGoToStartPage(browser);
В IE для всех зон включил "Защищённый режим" (чтобы не пришлось использовать манипуляции с InternetExplorerOptions.IntroduceInstabilityByIgnoringProtectedModeSettings). И всё заработало.

Конкретно код шаблонного метода навигатора, который помогает со страницы перейти на страницу указаного типа по клику на элемент выглядит так (код не самый красивый, но работает):
/// <summary>
        /// Переключение на новую вкладку/окно после щелчка по элементу
        /// </summary>
        /// <typeparam name="TPage"></typeparam>
        /// <param name="clickDestination"></param>
        /// <returns></returns>
        public TPage ToNew<TPage>(IWebElement clickDestination, int waitInSeconds = 20) where TPage : UiComponent, new()
        {
            ReadOnlyCollection<string> prevWindowsCollection = Browser.WindowHandles;
            To(clickDestination);
            /*
            if ((Browser as RemoteWebDriver).Capabilities.BrowserName == "internet explorer")
            {
                Browser.WaitForSeconds(10);
            }         
             */
            IEnumerable<string> newWindowsCollection;
            try
            {
                newWindowsCollection = Browser.WindowHandles.Except<string>(prevWindowsCollection);
            }
            catch (Exception exception)
            {
                throw new Exceptions.SeleniumHelperException(
                    String.Format("При щелчке по элементу {0} ожидалось открытие нового окна или вкладки. Но после щелчка количество окон/вкладок осталось прежним: {1}",
                        clickDestination,
                        prevWindowsCollection.Count
                        ),
                    exception
                    );
            }
            try
            {              
                if (newWindowsCollection.Count() == 1)
                {
                    Browser.SwitchTo().Window(newWindowsCollection.First());
                }
                else
                {
                    throw new Exceptions.SeleniumHelperException(
                        String.Format("При щелчке по элементу {0} ожидалось открытие нового окна или вкладки. Но после щелчка появилось новых окон/вкладок: {1} шт.",
                            clickDestination,
                            newWindowsCollection.Count()
                            )
                        );
                }
            }
            catch (Exception exception)
            {
                throw new Exceptions.SeleniumHelperException(
                    String.Format("При переключении на новую вкладку/окно произошла ошибка"),
                    exception
                    );
            }
            var startTime = DateTime.Now;
            var stopTime = DateTime.Now.AddSeconds(waitInSeconds);
            bool stopWait = false;
            TPage newPage = null;
            do
            {
                try
                {
                    newPage = new TPage();
                    stopWait = true;
                }
                catch (Exception exception)
                {
                    stopWait = false;
                    if (DateTime.Now >= stopTime)
                    {
                        var msg = String.Format("Новая вкладка открылась, но за {0} сек. страница не смогла инициализироваться", waitInSeconds);
                        throw new Exceptions.NotFoundElementException(msg, exception);
                    }
                }
            }
            while (!stopWait);

            return newPage;
        }

Метод возвращения на предыдущую вкладку/окно при закрытии текущей вкладки/окна выглядит так:
/// <summary>
        /// Переключение на предыдущую вкладку/окно после щелчка по элементу
        /// </summary>
        /// <typeparam name="TPage"></typeparam>
        /// <param name="clickDestination"></param>
        /// <returns></returns>
        public TPage ToPrev<TPage>(IWebElement clickDestination) where TPage : UiComponent, new()
        {
            ToPrev(clickDestination);
            return new TPage();
        }

        /// <summary>
        /// Переключение на предыдущую вкладку/окно после щелчка по элементу
        /// </summary>
        /// <typeparam name="TPage"></typeparam>
        /// <param name="clickDestination"></param>
        /// <returns></returns>
        public void ToPrev(IWebElement clickDestination)
        {
            ReadOnlyCollection<string> prevWindowsCollection = Browser.WindowHandles;
            To(clickDestination);
            ReadOnlyCollection<string> newWindowsCollection = Browser.WindowHandles;
            try
            {
                Browser.SwitchTo().Window(newWindowsCollection.Last());
                if (prevWindowsCollection.Count - newWindowsCollection.Count != 1)
                {
                    throw new Exceptions.SeleniumHelperException(
                        String.Format("При закрытии вкладки/окна количество вкладок/окон должно было уменьшиться на 1. Было {0}, стало {1}",
                            prevWindowsCollection.Count,
                            newWindowsCollection.Count
                            )
                        );
                }
            }
            catch (Exception exception)
            {
                throw new Exceptions.SeleniumHelperException(
                    String.Format("При закрытии вкладки/окна произошла ошибка"),
                    exception
                    );
            }
        }



#115390 Pattern page object - можно ли считать pop-up отдельной страницей?

Отправлено автор: owasp 04 марта 2013 - 16:03 в Selenium - Functional Testing

Если вы пишете тесты в стиле StronglyTypedPageObject, а именно, как-то так:
using MvcMusicStore.FunctionalTests.Step3.Pages;
using NUnit.Framework;
using FluentAssertions;

namespace MvcMusicStore.FunctionalTests.Step3
{
    public class StronglyTypedPageObjectWithComponent
    {
        [Test]
        public void Can_buy_an_Album_when_registered()
        {
            var orderedPage = new HomePage()
                .Menu
                .GoToAdminForAnonymousUser()
                .GoToRegisterPage()
                .CreateValidUser(ObjectMother.CreateRegisterModel())
                .GenreMenu
                .SelectGenreByName("Disco")
                .SelectAlbumByName("Le Freak")
                .AddAlbumToCart()
                .Checkout()
                .SubmitShippingInfo(ObjectMother.CreateShippingInfo(), "Free");

            orderedPage.Title.Should().Be("Checkout Complete");
        }
    }
}
Тогда есть явный смысл реализовать получение каждого объекта как PageObject.

Но более удачное решение - использовать PageComponent или HtmlElement в дополнение к PageObject. Паттерн PageComponent нестандартный, используется в TestStack.Seleno (.NET), см. http://teststack.github.com/. Аналогичный функционал для Java есть в разработке HtmlElement от Яндекс, см. https://github.com/y...s/htmlelements.

Оба подхода похожи, только языки разные. Описание преимуществ HtmlElement по сравнению с чистым PageObject есть в статье http://habrahabr.ru/...ex/blog/158787/ (Тестирование в Яндексе. Фреймворк HTML Elements: чего не хватает в Page Object, и как это исправить). В TestStack.Seleno нет поиска по относительным локаторам, как это сделано в HtmlElement, этот функционал дописал сам. А потом ещё его расширил возможностью поиска только видимых элементов по относительным локаторам.

В своей разработке не использую StronglyTypedPageObject, обхожусь возможностями простого подхода PageObject. Так как сценарий тестов формируется для TestStack.BDDfy, а там сценарий разделён на вызовы. И строится не цепочечно (как показано в примере кода выше). А более традиционно, похоже на:
using FluentAssertions;
using MvcMusicStore.FunctionalTests.Step2.Pages;
using NUnit.Framework;
using TestStack.Seleno.PageObjects;

namespace MvcMusicStore.FunctionalTests.Step2
{
    public class PageObjectWithComponents
    {
        [Test]
        public void Can_buy_an_Album_when_registered()
        {
            var orderedPage = PlaceOrder(homepage);
            orderedPage.Title.Should().Be("Checkout Complete");
        }

        private static Page PlaceOrder(HomePage homepage)
        {
            var shippingPage = homepage
                .GenreMenu
                .SelectGenreByName("Disco")
                .SelectAlbumByName("Le Freak")
                .AddAlbumToCart()
                .Checkout();

            shippingPage.FirstName = "Homer";
            shippingPage.LastName = "Simpson";
            shippingPage.PromoCode = "FREE";
            return shippingPage.SubmitOrder();
        }
    }
}

Отталкиваясь от TestStack.Seleno расширил и написал функционал для работы с компонентами (использую TestStack.Seleno не в чистом виде). (Страницы и компоненты) состоят из (компонент, IWebElement и SelectElement). Удобно.



#115389 события мыши (mousemove, mouseover) в webdriver

Отправлено автор: owasp 04 марта 2013 - 15:43 в Selenium - Functional Testing

MouseMove сделал через метод расширения для IWebElement (реализация C# для Selenium.WebDriver.dotnet40.2.31.1.0) см. метод MouseMove:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using OpenQA.Selenium;
using OpenQA.Selenium.Remote;

namespace NpoComputer.SeleniumHelper.Extensions
{
    public static class WebElementExtension
    {
        /// <summary>
        /// Поиск элемента с дополнительным Linq-фильтром
        /// </summary>
        /// <param name="driver"></param>
        /// <param name="by">Условие выборки списка элементов</param>
        /// <param name="predicate">Linq-фильтр</param>
        /// <returns>Первый элемент в результатах поиска с фильтрацией (если элемент существует)</returns>
        public static IWebElement FindElement(this IWebDriver driver, By by, Func<IWebElement, bool> predicate)
        {
            return driver.FindElements(by, predicate).First();
        }

        /// <summary>
        /// Получение списка классов элемента
        /// </summary>
        /// <param name="element"></param>
        /// <returns>Список классов</returns>
        public static ReadOnlyCollection<string> ClassList(this IWebElement element)
        {
            ReadOnlyCollection<string> classList;
            try
            {
                char[] arraySeparators = { ' ', '\n', '\t' };
                classList = element
                    .GetAttribute("class")
                    .Split(arraySeparators, StringSplitOptions.RemoveEmptyEntries)
                    .ToReadOnlyCollection<string>();
            }
            catch(Exception)
            {
                classList = new ReadOnlyCollection<string>(new List<string>());
            }
            return classList;
        }

        public static void MouseMove(this IWebElement element)
        {
            RemoteWebElement webElement = element as RemoteWebElement;
            RemoteWebDriver webDriver = webElement.WrappedDriver as RemoteWebDriver;
            webDriver.Mouse.MouseMove(webElement.Coordinates);
        }

        public static void ContextClick(this IWebElement element)
        {
            RemoteWebElement webElement = element as RemoteWebElement;
            RemoteWebDriver webDriver = webElement.WrappedDriver as RemoteWebDriver;
            webDriver.Mouse.ContextClick(webElement.Coordinates);
        }
    }
}

Вызов MouseMove для определённго элемента, реализующего IWebElement:
element.MouseMove(); //где element - объект IWebElement)



#115350 Проблема с тестировщиками

Отправлено автор: owasp 03 марта 2013 - 18:18 в Управление тестированием

Ребят, а как поступить в случае, если просто нет времени на обучение тестировщиков?

Они сами могут обучаться.

Но даже это требует времени. Формально процесс самообучения сводится к внутреннему обмену опытом в команде. Кто-то научился грамотно настраивать съём показаний счётчиков производительности и проанализировал какие из них важны, а какие не мало полезны. Кто-то грамотно настраивает proxy-сервера и мастерски отлаживает/замеряет/замедляет/... что-то с их помощью. Кто-то автоматизировал развертывание ПО в парке виртуальных тестовых стендов. И так далее.
Это надо заметить. Похвалить людей. Выделить время, чтобы они подготовились, как-то организовали знания по теме и рассказали о своём опыте коллегам (бывает, неделю надо готовиться к такому). Снова похвалить (поддержать общее одобрение проделанной работе).
Дальше можно сказать - мол, формализируй накопленный опыт, напиши инструкцию или руководство (на этом моменте можно зарубить стремление человека к дальнейшему самостоятельному изучению темы, если с его стороны ситуация будет выглядеть так: "напиши инструкцию, поставь точку и возвращайся к работе, дел полно", - то стремление изучать тему не усилится).
Или разобраться в вопросе, прикинуть как и где данные знания пригодятся, и спросить у человека совета, как лучше поступить вот так или вот так ... (не праздный интерес, а для пользы дела). Или ничего не делать, если люди самоорганизованные, они сами организуются.

Когда-то ведь работа, заканчивается. И вот тут стоит рассказать, как же она была сделана, и благодаря чему она была сделана хорошо. Конечно, если уйти в работу с головой, то всё вокруг кажется обыденностью, о которой и рассказывать не стоит (мол так всегда и было). Но всегда есть, о чем рассказать или написать.

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