en
Feedback
LikeaDuck🦆

LikeaDuck🦆

Open in Telegram

Дима Тучс (https://t.me/dtuchs). QA директор в DODO, спикер и программный комиттёр на конфах, создатель авторского курса QA.GURU Advanced. Здесь будет об IT, QA, менеджменте и немного обо мне.

Show more
1 450
Subscribers
No data24 hours
No data7 days
-830 days
Posts Archive
#Java #Spring Об обновлении зависимостей. Обновил тут в одном из своих Spring пет-проектов одну зависимость. Было 1.1.2, стало - 1.2.1. Поменял местами 2 цифры так сказать, что могло бы пойти не так? У меня напрочь отвалился Oauth 2.0 code flow. Запрос`/oauth2/token? отдает 400 BAD REQUEST. И говорит вот такое понятное сообщение об ошибке - UNSUPPORTED_GRANT_TYPE. Как же так, спрашиваю сам себя? Ведь я не менял grant_type=authorization_code в своем запросе; В коде спрингового сервиса даже в DEBUG логгировании нет никаких ошибок и стэктрейсов, потому что эта ошибка и не логгируется при выбрасывании. Что делать? Смотреть гит блэйм, кто же и что же поменял в этом OAuth2TokenEndpointFilter, чудес же не бывает? А изменения кроются, на самом деле, внутри OAuth2AuthorizationCodeAuthenticationConverter. Метод OAuth2EndpointUtils.getFormParameters раньше доставал из запроса и GET-параметры, и URL-encoded параметры, а теперь - только URL-encoded параметры. Как же так, почему раньше-то можно было? Иду в RFC Oauth 2.0 и вот ответ - The client makes a request to the token endpoint by sending the following parameters using the "application/x-www-form-urlencoded" То есть, еще месяц назад реализация OAUTH 2.0 в spring-authorization-server не соответсвовала RFC, принимая GET параметры! Так же ей не соответсвовал и мой код, отправляя GET параметры. Начав бомбить о том "да как так одна циферка зависимости ломает мой прекрасный код!" закончил философским "ошибаются все, и не боги горшки спринговые обжигают". Тут есть и еще один вопрос, а почему я вообще изначально не прочитал нормально RFC и отправлял GET-параметры? Потому, что до получения странной ошибки я просто думал, что мне будет достаточно посмотреть воркшоп автора книги Spring Security in Action - и в нем тоже показана отправка простых GET параметров. А значит, ошибаются не только контрибьюторы Spring, но и даже авторы книг о Spring. Мои выводы - ошибайтесь на здоровье; - но, любите дебаг; - и гитблэймы; - и чтение спецификаций и RFC

Вышел из отпуска :harold-the-pain: Провел собеседование (неудачно), узнал, что сегодня дедлайн по OKR на 1 квартал (они-то уже есть, но были не внесены в нужную эксельку). Узнал что у нас прямо сейчас все хотят открыть 5 QA вакансий: - Mobile QA - Team Lead QA - Performance QA - Web QA - Железячный QA 🙂 Пообсуждали архитектуру большого проекта Kotlin тестов и наметили, куда ее рефакторить. А еще пропустил обсуждение важного вопроса в слаке*:
Куда бежать в случае землетрясения в Алматинском офисе
Теперь надеюсь, что эти знания не пригодятся 🙂

Куда я пропал в 2024? В отпуск) Стараюсь сейчас вообще не думать ни о работе, ни о лекциях, ни о конференциях, пока получаетс
Куда я пропал в 2024? В отпуск) Стараюсь сейчас вообще не думать ни о работе, ни о лекциях, ни о конференциях, пока получается. Но отпуск закончится, и будет много о планах в Додо, планах в qa.guru и, конечно, технических постов. Stay tuned 🙌

Дорогие друзья, коллеги, я надеюсь вам так же было интересно в 2023 в этом канале, как мне самому - в дискуссиях с вами. В новом году будет кое-что действительно интересное от меня на поприще QA - я уже начинаю работать над действительно крутым проектом для всех нас. С новым годом!🎄

А еще сегодня маленький JUnit Extension, который дизэйблит тесты, если есть открытый issue (например, ваш тест нашел баг, и вы завели issue или ваш тест устарел, и вы завели issue на его актуализацию): 1) Создаем аннотацию
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(IssueExtension.class)
public @interface DisabledByIssue {
  String value();
}
Именно в ней будет id (номер) заведенного issue 2) Пишем Extension
public class IssueExtension implements ExecutionCondition {

  private static final OkHttpClient httpClient = new OkHttpClient.Builder().build();
  private static final Retrofit retrofit = new Retrofit.Builder()
      .client(httpClient)
      .baseUrl("https://api.github.com")
      .addConverterFactory(JacksonConverterFactory.create())
      .build();

  private final GhApi ghApi = retrofit.create(GhApi.class);

  @SneakyThrows
  @Override
  public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
    DisabledByIssue disabledByIssue = AnnotationSupport.findAnnotation(
        context.getRequiredTestMethod(),
        DisabledByIssue.class
    ).orElse(
        AnnotationSupport.findAnnotation(
            context.getRequiredTestClass(),
            DisabledByIssue.class
        ).orElse(null)
    );

    if (disabledByIssue != null) {
      JsonNode responseBody = ghApi.issue(
          "Bearer " + System.getenv("GH_TOKEN"),
          disabledByIssue.value()
      ).execute().body();

      return "open".equals(responseBody.get("state").asText())
          ? ConditionEvaluationResult.disabled("Disabled by issue #" + disabledByIssue.value())
          : ConditionEvaluationResult.enabled("Issue closed");
    }
    return ConditionEvaluationResult.enabled("Annotation not found");
  }
}
3) Ну и запрос в github для retrofit:
public interface GhApi {

  @GET("/repos/qa-guru/niffler/issues/{ISSUE_NUMBER}")
  @Headers({
      "Accept: application/vnd.github+json",
      "X-GitHub-Api-Version: 2022-11-28"
  })
  Call<JsonNode> issue(@Header("Authorization") String bearerToken,
                       @Path("ISSUE_NUMBER") String issueNumber);
}
Я глубоко убежден, что если тест начал падать, то на это должен быть issue (если, конечно, там не на 5 минут исправить ситуэйшн). А если уж мы создаем issue, давайте дизэйблить тесты, как Петербуржцы

А вот и баг в нашем курьерском приложении, про который я хотел рассказать. Главный экран приложения (картинка, где заказ 148-
+1
А вот и баг в нашем курьерском приложении, про который я хотел рассказать. Главный экран приложения (картинка, где заказ 148-2) включает в себя список готовящихся и уже приготовленных заказов. Курьер (я) видит, что готов заказ, и выделяя его, свайпает "Поехали!". После этого мы попадаем на второй экран (на моих картинках - где 220-4). Этот экран содержит чекбоксы всех продуктов в заказе, которые надо проставить, складывая пиццы и додстеры с соусами в термосумку. Чекк-лист, что бы клиент получил ровно то, что заказывал, и ничто "случайно" не оказалось забыто. Так вот, как выяснилось, в момент перехода с первого экрана на второй, заказ не фиксируется за выбравшим его курьером! Реальное назначение на курьера происходит только после завершения "чек-листа" на втором экране. Таким образом я старательно складывая заказ в свою сумку сталкиваюсь с тем, что ко мне подходит мой коллега курьер и говорит "А чего это ты мой заказ тут собираешь? Он же мой, я его взял!". И действительно - я смотрю в свое приложени и вижу, что заказ-то уже не мой и я зря тут галочки жму в чеклисте. Курьеры, кто работают постоянно, конечно знают про эту особенность, и поэтому у них флоу такой - "Выбрать заказ -> Моментально прощелкать галочки чеклиста (тем самым превратив его в фикцию) -> Тем самым по-настоящему забронировать заказ за собой -> Пойти собирать его в сумку". Этот баг - на мой взгляд - очень серьезный, так как он выкидывает в помойку целый бизнес-процесс - проверка заказа по чеклисту. Этот этап просто скипается, что бы никто другой не взял тот заказ, что ты планиурешь везти. А еще, это очень похоже на то, как если бы сайт РЖД не резервировал для вас билет, пока вы вводите свой номер кредитки🥲

Кстати, не обошлось без интересного бага. Завтра расскажу. А это мы с СЕО Dodo Engineering встретились за полезным делом пере
Кстати, не обошлось без интересного бага. Завтра расскажу. А это мы с СЕО Dodo Engineering встретились за полезным делом перед пиццерией)

Курьерю для души, а так я head of qa
Курьерю для души, а так я head of qa

Все готово к стриму, жду через 39 минут 🎄
Все готово к стриму, жду через 39 минут 🎄

#обучение #java #qaguru А еще сегодня стартую 4 поток своего авторского курса Advanced. Занятие отрытое для всех, так что приходите, даже если не хотите учиться. Ну а если вдруг думаете - надо оно вам или нет - посмотрите на один из лучших дипломов 3 потока от от Миши Нестерова - проект Rococo Фронтенд (rococo-client) к нему написан нашей командой, а именно Ириной из OZON fintech, но, каждая другая строка кода, каждый микросервис, каждая строчка тестов, и все-все все в этом репозитории - написал Миша, и это и есть наш диплом. Мы даем front, остальное делают студенты. На 4-м потоке мы будем давать целых два frontend-а на выбор (REST и GraphQL, совершенно разные проекты), а все бэкенды и тесты будут писать студенты. Будет очень 🚀 интересно 🚀. Промокод в закрепе 😁

Сегодня на собеседовании спросил у QA инженера, у которого в резюме питон и джава/котлин: -
что больше всего тебе, как инженеру (автоматизатору), кажется главным отличием питона от джавы? Что тебя радует или огорчает при переходе с одного языка на другой?
Что бы вы ответили, если владеете обоими языками?

Хороший бонус работы в IT компании, связанной с offline бизнесом - возможность поработать в этом самом бизнесе. Планирую неск
+1
Хороший бонус работы в IT компании, связанной с offline бизнесом - возможность поработать в этом самом бизнесе. Планирую несколько дней работать курьером, разносить нашу додо-пиццу по Алматы. Отпишусь, заработаю ли сколько-нибудь чаевых, или наоборот, сколько человек посмотрит на меня, как на 💩) Ну и заодно посмотрю, как на самом деле работают наши IT продукты - тут потрогаю все, что связано с доставкой, на проде🙂. Кстати, наш СЕО тоже будет курьером. И еще несколько ребят из QA, конечно же 🍕

Маленькая новость выходного дня. Сам забыл (и вспомнил благодаря рассылке в чате qa.guru), что сегодня последний день общедоступной скидки 10% на мой курс Advanced, которая прекрасно суммируется с моим промокодом. Итого, 15% скидка на курс, который я стартую уже в эту среду, 21 декабря. Залетайте смотреть кодовую базу, смотрите тесты, экстеншены и все-все все в репо. Именно этому будем три месяца учиться онлайн на лекциях со мной (в основном) и не только🚀. Кому интересно - welcome aboard! А еще мы уже пишем учебное IOS приложение Niffler, заканчиваем с фигмой редизайна, и планируем писать Android приложение. Stay tuned!

#этоневажно Об ачивке, формулировке, должности - SDET. Что это такое? Что он должен уметь из того, что не должен уметь QA Automation Engineer? Я глубоко убежден что эту формулировку придумали из двух соображений: 1) Потешить свое ЧСВ. Уж больно не охота называться "всего лишь QA". Как бы стоять в одном ряду с джуниором, закончившим курсы и прочитавшим пару книг. А я, мол, целый SDET, знаю про докер, CI/CD умею, написал свой собственный фреймворк для отправки HTTP запросов и обернул методы селенида / плэйрайта кучей своих очень необходимых оберток! Я не просто "QA" - который умеет написать тест из шагов, я целый SDET! Это примерно как если бы условный fronted developer с какого-то момента начал называть себя Software Engineer In Browser. SEIB. Что я не просто там верстаю и джсоны парсить умею, я ого-го. Не правда ли звучит потешно - придумывать понтовую доллжность? Но SDET-ы, конечно, считают что это звучит гордо. Что им, наверное, за это надо платить больше, или что их больше зауважают "настоящие разработчики и инженеры"🙂 2) И второй аргумент - я не хочу ручного тестирования, я только пишу код. Этот аргумент тоже не выдерживает критики, т.к. любой код написанный кем либо - он не висит в воздухе. Вокруг него всегда есть что-то до и после. И если для написания теста (зафиксировать поведение системы) надо проверить что это поведение вообще соответствует ожидаемому руками - это не "стремно", а нужно. Если для написания теста надо разобраться, как поднять тестируемую систему в docker-compose и положить в нее тестовые данные - это просто надо уметь и мочь сделать. Совершенно не важно, впишите вы себе в резюме эти 4 буквы или нет. Важно то - понимаете ли вы своя ЯП, понимаете ли вы - что такое DevOps практики, умеете вы сами работать с инфрой, скриптами на CI/CD, умеете ли вы сами поработать с обсервабилити, а не тупо смотреть на графики в графане, которые сделал кто-то до вас. Разберетесь вы с проблемами в вашем докере, или нет. Сможете ли принести Pull-Request в Аллюр, Селенид или любой другой опенсорс, когда найдете там баг. Сможете собрать свой образ браузера для Selenoid или понять, что не так с конфигом nginx, почему вы вдруг получаете ConnectionRefused. Сможете ли вы не писать свои фреймворки, а сделать так просто, как только можно. Сможете ли сделать простой DSL создания тестовых данных, будь то json или аннотации/декораторы над тестом. Это все умения Senior QA Automation - а 4 буковки еще ни разу не смогли мне объяснить - почему их надо величать именно так, а не иначе. Не стремитесь повесить на себя такую ачивку, у самых крутых экспертов в их линкединах и резюме зачастую написано просто "QA", эксперта красят не 4 буквы SDET.

#Java #gradle #automation Вчера один из моих студентов задал вопрос -
Добрый день! Кто может подсказать какой JDK 17 версии нужно поставить чтобы не было конфликтов и можно было использовать selenide 7? Если выбираю JDK 17 версии , то ловлю ошибку "Could not initialize class org.codehaus.groovy.reflection.ReflectionCache"
Ну и скрин с этой ошибкой. Опыт не пропьешь - я сразу сказал, что, видимо, gradle в проекте / системе не той версии, которая нужна для Java 17 (это версии 7.6 и выше). Студент стал разбираться и - конец немного предсказуем - дело было действительно в старой версии gradle (6.7). Обновили и все заработало. И тут у меня один вопрос - неужели невозможно, если уж вы делаете разбивки по версиям, которые совместимы с той или иной JDK, неужели совсем невозможно вывести понятное сообщение об ошибке - "Дружище, у тебя несовместимые версии". Как новичок должен разбираться в
Could not initialize class org.codehaus.groovy.reflection.ReflectionCache
? У меня нет ответа.

Кстати, мы еще делаем небольшой QA митап в Москве - но, без моего присутсвия😔. 12 декабря в офисе Dodo Brands в Москве. За меня там будет лидер гильдии Web QA Женя Иванченко. В программе разговор о том, как командам быстрее передавать фичи бизнесу и писать эффективные ассерты в интеграционных тестах. Приходите, будет интересно! Ну и офис наш, в предновогоднюю пору, крутой 💔 Участвовать можно онлайн или оффлайн (пиццу есть точно удобнее оффлайн), регистрация по ссылке до 10 декабря 👉🏻 https://qa-dodo-spb.timepad.ru/event/2670046/ А почему не будет меня? Мы устраиваем съезд лидеров QA направлений DODO в Алмате ровно в эти же даты. Будем вживую прожаривать OKR-ы, родмапы и вот это все на 2024 год.

❓ Как проходит обучение и развитие QA-инженера внутри компаний? Об этом мы поговорим 7 декабря в 20:00 по Москве за круглым с
Как проходит обучение и развитие QA-инженера внутри компаний? Об этом мы поговорим 7 декабря в 20:00 по Москве за круглым столом. 🗓 Добавить напоминание Сильнейшие специалисты отрасли: Инна Чернобровкина, Ян Акмеев и Дмитрий Тучс соберутся в прямом эфире, чтобы поделиться своим опытом и обменяться мнениями. 💡 Что мы обсудим? • Пути и планы развития тестировщиков внутри компаний • Сложности и ловушки при создании корпоративной школы • Секреты формирования библиотеки полезных ресурсов для QA • Взгляд на внешние курсы: стоит ли отправлять туда специалистов? • Все за и против различных форматов обучения QA • Актуальные варианты обучения для QA – инженеров внутри компаний 🔥 Мы приглашаем вас не просто послушать, но и активно участвовать в дискуссии! Задавайте свои вопросы в чате стрима и получайте ответы от наших экспертов. 🔗 Ссылку на трансляцию мы опубликуем в день выхода в эфир в 19:55 МСК в нашем чате, а так же продублируем вам на почту.

Интересный контент должен подъехать на следующей неделе - буду за круглым столом обсуждать обучение QA😈. Свою первую школу автоматизации внутри PropellerAds организовал 4 года назад, ещё до прихода в qa.guru. Мне определенно есть, что сказать )

Ребят, а вдруг есть среди моих подписчиков кто-то, кто хотел бы поработать QA на стыке с бизнесом, то есть, автотестов особо писать не надо (можно и не уметь), а вот погрузиться в бизнес, понять как работают додо-курьеры, какие там проблемы и особенности, хотел бы? Мы запускаем амбициозный проект переделки бизнесфлоу доставки нашей пиццы под кодовым названием "курьер-на-город". Там нужен qa , уровень middle+ и выше. Повторюсь - вакансия не про тесты пописать, а про погрузиться в бизнес, мыслить как курьер (и заказчик пиццы) и находить проблемы именно, в первую очередь, в недодуманных бизнес-сценариях. Если кто-то заинтересован, напишите пожалуйста мне в ЛС или в комменты к посту. Созвонимся, все расскажу.

#automation #этоневажно Ввожу новый хэштег - #этоневажно. Дело в том, что я уже годы наблюдаю упертое желание потешить свое ЧСВ казалось бы важными постулатами в автоматизации, но большинство из них на самом деле не важны. Сегодня рассмотрим классику - PageObject (тут и далее как обычно все на Java). Что важно для PageObject? 1) PageObject объект должен создаваться максимально просто - читай, через new (безо всяких PageObjectFactory) 2) Он должен быть immutable и никогда не иметь никакого shared mutable state - читай, все поля final , а static - только для immutable констант 3) Он должен использовать композицию, а не наследование для расширения функциональности (то есть, если у нас есть LoginPage с двумя полями логин и пароль, и RegistrationPage с тремя полями - логин, пароль, повторипароль, то мы не делаем RegistrationPage extends LoginPage). Вообще, наследование почти никогда не нужно в тестах на самом деле. Все остальное, что я годами читаю в умных чатах по автоматизации, да и на code-review - не важно. Примеры: - Стэпы должны быть в отдельном классе! Или наоборот - стэпы должны быть только в PageObject! - это вообще не имеет никакого значения, лишь бы было где-то прописано прямо в ридми. Никакой технической разницы нет, разве что вам приятно писать больше отдельных step-классов; - Селектор должен быть CSS ! или XPATH!. Селектор вообще никому ничего не должен. В реальной жизни к нему только одно требование - селектор не должен быть всратым. Но это не зависит от того CSS он или XPATH - Методы должны возвращать this! Или не должны! Или должны, но не всегда! - это не влияет никак ни на скорость написания тестов, ни на поддерживаемость, ни ну удобство рефакторинга. - При композиции ты должен дублировать все методы вложенного объекта / Ты должен просто написать геттер! - можно и так и так - Ассертов в пэйдж обжекте быть не должно - встречал и такое 🥲 - Имена полей должны начинаться со слова element! Или заканчиваться им! и т.д. и т.п. Обращайте внимание только на то, что действительно (технически) важно: иммутабельность, простота инициализации, композиция вместо наследования.