Multiple choice grid что это

Обновлено: 05.07.2024

TypeError: Cannot find function setColumns in object Item. (line 26, file "Populate Hazard Choices").

I've tried setColumnChoices and setColumns and seem to have the same bad results.

The plan is to have the Grid Columns be populated from a Sheet called "DataFactors" so that any changes to the list of hazards will populate exactly the same on the Form. When the user submits a Form, the choices are compared to the sheet and a point value is assigned. Hopefully this will solve a problem with mis-compares between the Form submissions and the Hazard values. I have had good results using Dropdown lists but can't seem to make the method work for Multi Choice Grids.

Диагностика грамматических ошибок при изучении английского языка

В этой публикации я расскажу (и снова поделюсь API) о гораздо более информативном варианте грамматического multiple choice. Главное его достоинство — функция диагностики грамматических ошибок при изучении английского языка.

Как выполнять много UI-тестов параллельно, используя Selenium Grid?

Всем привет! Я работаю в Avito и занимаюсь разработкой инструментов для тестирования. Когда у нас стало много UI-тестов, мы столкнулись с проблемой масштабирования Selenium-серверов, и сейчас я расскажу, как мы ее решили.


Небольшое отступление, о том как работает Selenium-сервер.

  • Для того, чтобы начать управлять браузером нужно послать запрос create session на Selenium-сервер.
  • В результате на ноде открывается браузер, а к вам возвращается токен sessionId , отправляя который в каждом запросе, вы управляете браузером.

Окей, а зачем нужен Selenium Grid? Selenium Grid предоставляет единую точку для работы со множеством Selenium-серверов разной конфигурации:

  • он позволяет создавать сессию на свободной ноде, подходящей под ваши критерии фильтрации, например, по версии браузера;
  • хранит информацию о том, какая сессия открыта на какой ноде и проксирует все запросы на целевую ноду, таким образом для клиента нет разницы работать с одной нодой, или с гридом.


Замечательный инструмент, правда?


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

1. Непредсказуемое поведение
Если кратко, то у вас отвалится что захочет и когда захочет, и вы никак не сможете на это повлиять.

  • Мы очень часто сталкивались с ситуациями, когда тесты отлично работали в один поток, но при многопоточном выполнении через грид были непредсказуемые падения.
  • Периодически на часть нод тесты просто не попадали, хотя физически они были доступны, на гриде скапливалась очередь из тестов. В итоге половина релизного сьюта отваливалась по таймауту.

2. Отсутствие поддержки большого количества нод
При попытке зарегистрировать много нод (а мы хотим много нод), регистрация произойдет, но протестировать приложение во много потоков все равно не получится, так как большая часть тестов упадет.


3. Масштабируемость
Первое, что приходит в голову, когда достигнут предел нод = N на селениум гриде, при котором не страдает стабильность, — это взять два, три, пять, (да хоть десять) гридов, зарегистрировать на каждый по N нод, вкрячить перед всем этим добром какой-нибудь балансировщик и запускать тесты в 10*N потоков. Но нет, Selenium Grid так не работает. Потому что вся информация о нодах и сессиях хранится в памяти у конкретной ноды и не шарится между ними. С этим тесно связана следующая проблема.


4. Отказоустойчивость
Если у вас выключается машина, где находится хаб, то все тесты сразу умирают, потому что у вас нет никаких резервных хабов, на которые могут идти следующие запросы, ибо опять же, все лежит в памяти. И это абсолютно никак не смасштабировать (конечно же, всегда можно переписать пару классов грида, но об этом позже). Слабое место — это Selenium Hub, при его падении ноды становятся недосягаемыми.


5. Отсутствие возможности динамического создания нод с использованием система оркестрации контейнерами
Если для тестирования вам необходимо множество различных конфигураций нод с разными конфигурациями браузеров, то возникает еще одна проблема: весь этот зоопарк занимает довольно много места в памяти. Предположим, у вас: 300 нод с Google Chrome (150GB RAM) + 300 нод с Firefox (150GB RAM) и еще 200 нод какого нибудь Firefox Nightly c магическими плагинами (100GB RAM). 400GB RAM постоянно заняты, плюс хочется эффективно перераспределять ноды в течение дня, скажем, занять все 400GB семью сотнями хромов при тестировании одного сьюта и гибко заменять их при появлении в очереди тестов с другими потребностями.

Для решения этой задачи идеально подойдет Docker, так как он позволяет быстро поднимать контейнер со свежим Selenium и так же быстро его убивать после завершения теста. И так как селениумов нам нужно много, на один железный сервер все это не влезет, возникает потребность в оркестрации контейнеров на кластере. На рынке существует несколько популярных решений для этой задачи, у нас используется Kubernetes. Почему мы выбрали Kubernetes, можно послушать здесь. Стандартными средствами Selenium эту проблему не решить.

6. Невозможно обновить/перезапустить грид без даунтайма
Еще одно следствие хранения сессий в памяти. Не то чтобы это суперкритичный минус, но всё равно неприятный.

Все вышеперечисленное — это ситуация, в которой мы в один прекрасный момент оказались.

Известные решения

Grid Router и новая реализация Go Grid Router — хорошее решение, но к сожалению далеко не идеальное. Основная проблема особенность, то что это не замена для Selenium Hub, это еще одна прокси сверху.

Отсюда и название — Grid Router, потому что он управляет не нодами, а гридами, поэтому есть минусы.

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

Selenoid — средство для запуска тестов в docker-контейнерах. При каждом запросе на создание сессии запускается свежий контейнер и при закрытии сессии удаляется. Инструмент замечательный, но есть минусы:

  • не поддерживает ни одну систему оркестрации;
  • все еще хранит информацию о сессиях в памяти, и, как следствие, имеет проблемы с масштабированием и отказоустойчивостью.

Когда мы столкнулись со всеми этими проблемами, мы решили поинтересоваться опытом других компаний. «Яндекс» писал в блоге на Habrahabr о том, что не получается регистрировать много нод и работать с ними, для решения этой проблемы они используют Grid Router. Для наших задач Grid Router не подходит.

«Альфа-Банк» писал о том, что у них все повисает, если grid какое-то время не использовать, и наш опыт это подтверждает — у нас то же самое было регулярно.
Конечно же мы не обделили вниманием github selenium, где нашли несколько issue… Вот пример отношения авторов к происходящему:

Q: «selenium-grid version 3.0+ support hub high availability?»
A: «I would recommend having a separate server monitor the hub and then if/when the hub goes down it would know how to restore the hub.»

Мы поняли, что надеяться нам не на что, и стали сами решать свои проблемы.

Исследование

Мы решили начать с простого пути, задеплоили в kubernetes кластер некоторое количество селениумов, сложили ip в БД и непосредственно в setUp() теста ходили в базу брали оттуда ip, который дольше всех не использовался и запускали тест, нигде не храня sessionId и не блокируя ноды. Так как воркеров с тестами было < количества селениумов, переполнения не должно было происходить.

Это решение сразу показало свою жизнеспособность.

  • предсказуемое поведение;
  • отказоустойчивость на уровне БД;
  • масштабируемость;
  • поддержку большого количества нод;
  • upgrade без остановки тестов, потому что это просто код, который лежит у вас в репозитории, и запускается, когда запускаются тесты.

Но столкнулись с рядом проблем:

  • нет поддержки механизма выбора Capabilities;
  • нет удобного механизма /grid/register;
  • отсутстует Portability — система больше не работает как сервис, зависит от одного языка программирования и реализована в одном репозитории с тестами.

Последняя проблема — самая важная, потому что если вы зашиваете это в код тестового фреймворка, то вам автоматически нужно поддерживать это в каждом вашем тестовом фреймворке, во всех репозиториях на всех используемых языках.

Самое главное в этом эксперименте — полученный опыт. Мы убедились в том, что Selenium Grid можно реализовать нормально.

2 Answers 2

Just a few recommendations for you regarding your answer:

The above line should be replaced with the one below and your code will run faster and be more reliable.

It would be better to rewrite the above function in the following way:

Using getLastRow() is much better since using getMaxRows() can result in getting a lot of null values at the end of your data and often will result in errors.

Again sheetValues is not defined in this function and the following rewrite would improve readability greatly.

I was not trying to be rude or unkind. Your previous code had some serious problems and you addressed them and got it to run. That's what we like to see. Good work.

Окончательное решение

Первым делом мы стали рассматривать идею с форком/пулл реквестом селениума. Но после более детального знакомства с кодом проекта мы поняли, что дешевле и надежнее писать свой велосипед.

Давайте еще раз перечислим, что мы хотим от нового инструмента:

  • предсказуемость поведения;
  • отказоустойчивость;
  • масштабируемость;
  • portability;
  • поддержка большого количества нод;
  • поддержка Capabilities;
  • on-demand Node in Kubernetes;
  • сбор метрик в statsd;
  • механизм /grid/register;
  • upgrade без остановки тестов.

Что в итоге получилось:

  • приложение, которое решает все вышеперечисленные задачи;
  • кроссплатформенное приложение, тестировали на linux и macos;
  • написано на Go;
  • хранит данные в mysql.

В итоге нам удалось решить все задачи. Приложение написали на Go. Само приложение stateless — сессии хранятся в mysql, при желании не сложно поддержать любую другую БД. On-demand создание контейнеров реализовано только в Kubernrtes, но вы можете прислать пулл реквест с реализацией методов создания/удаления контейнера в любой другой системе. Go компилируется под разные платформы, но нам достаточно было протестировать работоспособность только на linux и macos, в теории других системах проблем быть не должно.

Теперь главный вопрос. Сколько нам строчек кода тестов пришлось переписать в процессе перехода на этот инструмент? Кто считает, что 10000/1000/100? Ноль! Ничего не надо было переписать, он полностью совместим. Просто нужно задеплоить приложение и указать его адрес, и все. Больше ничего делать не надо.

В итоге получилась такая схема:


Как этим пользоваться? Есть 2 режима:

  • Persistent — здесь всё как раньше, запускаете селениум сервер c параметром -role node , указываете где адрес хаба, нода регистрируется, можно пользоваться:
  • On-demand — в конфиг грида нужно добавить докер-образы и информацию о том, какие capabilities они реализуют. Дальше запускаете грид, запрашиваете сессию, нода сама создается в кластере.

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

Populate multiple choice grid from sheets

thanks to all, in advance, for any support you might be able to provide! I'm trying to populate a Multiple Choice Grid in Google Forms from Google Sheets. I've been able to populate dropdowns, but not grids. Here is the code I'm using for a grid:

Any suggestions would be highly appreciated! Thank you.


4,190 2 2 gold badges 8 8 silver badges 21 21 bronze badges


How unkind and rude. In any case, I troubleshooted it and solved it, no thanks to you, Cooper.

Диагностирующая функция заданий типа multiple choice

Но неправильных вариантов несколько. Можно ли узнать больше из того, как именно ответил ученик? Да, и именно с этим связана диагностирующая функция multiple choice. При составлении подобных заданий к каждому неправильному варианту «привязывается» какой-то тип ошибки, который поможет определиться с тем, какой материал стоит подучить, чтобы избежать этой ошибки в дальнейшем.

Например, изучающие английский язык часто забывают формы неправильных глаголов. Чтобы понять, что у данного пользователя именно эта проблема, необходимо создать такое задание, в котором среди неправильных вариантов была «проблемная» форма:

Вариант ответ под номером 1 — как раз диагностирует такую проблему (неправильно образованная форма глагола). Вариант 2 диагностирует проблему неразличения Past Simple и Past Progressive. Вариант 3 — правильный ответ, вариант 4 — глагол не стоит в нужной форме.

Именно эти проблемы решает API, которое я коротко опишу ниже. API работает с любым текстом на английском языке (при условии, что этот текст написан на правильном и нормативном языке — на других текстах изучать язык невозможно). Результатом работы является список уже готовых заданий типа multiple choice.

Например, предложение Jack London lived in San Francisco. получит такой ответ:

Обратите внимание, что теги не показываются пользователю, так как они как раз и описывают наличие проблемы и нужны системе (или учителю) для планирования дальнейших действий. Например, в ответе 2 вместо правильной формы Past Simple (past_simple_usage) предложена форма Past Progressive (past_progressive_usage), правила использования которых стоит повторить, если пользователь выбрал этот вариант. Также здесь рекомендуется повторить образование Past Simple (past_simple_construction).

Если к каждому тегу (или группе тегов) привязать текст с объяснением грамматического материала, то можно легко создать адаптивный курс грамматики на произвольном материале, который интересен и полезен пользователю.

Сейчас система поддерживает все основные видо-временные формы в активном и пассивном залогах. Это позволяет создать индивидуализированную систему обучения грамматике английского языка на практически любом материале, который интересен и полезен пользователю.

Читайте также: