Pull to refresh
56
0
Dmytro Zharii @Dmitry_Zhariy

Пользователь

Send message
Очень классно сделано!

Скрипт для прохождения (или тестирования): gist.github.com/dzharii/1fce1ef335d0073c0ded
Откройся!
// https://gist.github.com/ejoubaud/7d7c57cda1c10a4fae8c
Podium = {};

Podium.keypress = function(k) {
    var oEvent = document.createEvent('KeyboardEvent');

    // Chromium Hack
    Object.defineProperty(oEvent, 'keyCode', {
                get : function() {
                    return this.keyCodeVal;
                }
    });     
    Object.defineProperty(oEvent, 'which', {
                get : function() {
                    return this.keyCodeVal;
                }
    });     

    if (oEvent.initKeyboardEvent) {
        oEvent.initKeyboardEvent("keydown", true, true, document.defaultView, k, k, "", "", false, "");
    } else {
        oEvent.initKeyEvent("keydown", true, true, document.defaultView, false, false, false, false, k, 0);
    }

    oEvent.keyCodeVal = k;

    if (oEvent.keyCode !== k) {
        alert("keyCode mismatch " + oEvent.keyCode + "(" + oEvent.which + ")");
    }

    document.body.dispatchEvent(oEvent);
};


var keyb = {
    up:38, // Up
    right:39, // Right
    down:40, // Down
    left:37 // Left
};



function Play() { 
    var gameWrap = document.getElementById("game-wrap");
    var ds = gameWrap.dataset;

    var eggs = {
        downLeft:   ds["egg-0"], 
        topLeft:  ds["egg-1"], 
        topRight:  ds["egg-2"], 
        downRight: ds["egg-3"]
    };
    console.log(eggs);

    if (eggs.topLeft == 5) {
        Podium.keypress(keyb.left);
        Podium.keypress(keyb.up);
        console.log("topLeft");
    } else if (eggs.downLeft == 5) {
        Podium.keypress(keyb.left);
        Podium.keypress(keyb.down);
        console.log("downLeft");
    } else if (eggs.downRight == 5) {
        Podium.keypress(keyb.right);
        Podium.keypress(keyb.down);
        console.log("downRight");
    } else if (eggs.topRight == 5) {
        Podium.keypress(keyb.right);
        Podium.keypress(keyb.up);
        console.log("topRight");
    }

}
setInterval(Play, 10);



Геймплей:

Я пользуюсь XMind уже более 2-х лет.
Look&Feel у него свой
Сам Thread.Sleep ничем не плох и не хорош.
В моем коде, Thread.Sleep(100) используется для задержки на 100 миллисекунд в цикле, ожидания элемента для того, чтобы не напрягать браузер частыми запросами.

Т.е. в худшем случае, вы потеряете 1/10-ю секунды при ожидании одного элемента. Все относительно.
Для WebDriver тестов — это мало. Для юнит тестов и торговле на бирже ценных бумаг — это много.

Плохой практикой Thread.Sleep() становится, когда люди указывают константное время, например, 5 секунд для ожидания элемента.
Потом оказывается, что в IE, нужно подождать 10 секунд…
Тогда меняют Thread.Sleep(5000) на Thread.Sleep(10000)… и теперь тесты во всех браузерах работают со скоростью самого медленного.

Вот это — плохая практика.

Очень рекомендую записать скринкаст с демонстрациией возможностей фреймворка.
Для начала, простой «Getting Started… „

Только не в виде “вебинара», которые очень скучные и длинные, а в стиле Pluralsite или Lynda.

Я заметил, что запись моего «кодирования» можно ускорить в 2-4 раза, при этом, видео не потеряет в качестве. А всякие длинные установки, билды и скачивания можно и вовсе вырезать.

На видео потом, можно наложить как русскоязычную так и англоязычную звуковую дорожку. А следующую статью составить на основе уже записанного видео.

Удачи вам, Сергей, с проектом и последующим маркетингом :D
Сергей, не в обиду, но я читал вашу статью год назад. И через год… ваш стиль написания статьи полон сумбура.
Вы пытаетесь охватить всё на свете в одной теме. Становится непонятно, для кого эта статья написана.

Если вы хотите, чтобы начинающие автоматизаторы попробовали ваш фреймворк, то я рекомендую начать с более простой обзорной статьи и видео демонстрации работы, развивая более глубокие темы в следующих.
Если это только первая версия и MVP (Minimum Valuable Product) – то должен сказать, что получилось достаточно хорошо. Все таки написать с скомпоновать что-то и отдать «критикам» все во много лучше, чем спросить «Ребята, я тут книгу пишу, не подскажите о чем лучше написать?» – как это делают другие.
Успехов с версией 2.0!
какой-то мега-старый пароль, явно даже не прошлого года.

password2010?
А я же ведь предсказал… :)

Честно сказать, книга мне не показалась очень полезной. Возможно потому, что ваши статьи читал раньше, особенно те холиварные на ДОУ и Хабре. В свое время это было очень круто. Сейчас же, я хотел бы видеть более рафинированные мысли: избавится от неактуальных фактов, дать более чёткий совет.

Вот например из последней статьи (31 марта 2013 г.):
«Недавно проскользнула довольно-таки интересная статья о том, что в одной из
известных сервисных компаний собраны все ИТ-знания мира»

Хм… очень смутно представляю что такое недавно сейчас… для середины 2014-го года.
В общем, я бы хотел видеть рассказ о прошлых поступках и о топ как бы Автор поступил сейчас, больший багаж опыта за спиной. Ну что-то в таком духе.

А за бесплатную электронную книгу без СМС и регистрации – спасибо!
Не могу определится, а Через %опу + итерации, это можно назвать «Agile собственного приготовления»?
Treshnikov, спасибо за то, что делитесь информацией, а особенно об использовании WebDriver с PageObject'ами.

Разрешите мне также поделится теми наблюдениями, чем мой подход при работе с WebDriver отличается от вашего:

Сразу скажу, что у вас хорошее решение со Step(“step step step”) ;)

1. Я бы сразу разделил код на 3 проекта: отдельно тесты (AcceptanceTesting.Tests), отдельно библиотека с PageObject (AcceptanceTesting.TestModel), отдельно другие библиотечные функции (AcceptanceTesting.Core). – к этому все равно приходят, когда тестов станет много и их захочится разделить на несколько тестовых наборов для запуска параллельно

2. Для себя я выработал правило: стараться не использовать вебэлементы и другие вызовы вебдрайвера непосредственно в тесте, а использовать только вызовы методов PageObject.
Т.е. сделать так, чтобы тесты не знали, что они работают с WebDriver.

Вот, например, этот код я бы оставил не измененным:

Step("Ввод запроса 'смс автоматизация'",
       () => googleSearchResultPage = googlePage.EnterSearchText("смс автоматизация"));


А вот этот бы заменил

Step("Первая ссылка должна содержать адрес sms-automation.ru",
() =>
{
      var href = googleSearchResultPage.FirstLink.GetAttribute("href");
      Assert.AreEqual(href, "http://www.sms-automation.ru/");
});


на

Step("Первая ссылка должна содержать адрес sms-automation.ru",
() =>
{
      var href = googleSearchResultPage.GetFirstLink();
      // или 
      // var href = googleSearchResultPage.GetAllLinks().First();
      Assert.AreEqual(href, "http://www.sms-automation.ru/");
});


Спасибо вам еще раз, за то, что делитесь знаниями и хорошими подходами!

Минутка самопиара:
А посмотрите ещё мой Page Recorder, который может ускорить процесс создания PageObject классов.
Я считаю, что это круто. Думаю, что сейчас, конечно, не так много найдется людей, который бы работали с екселем и умели рабоать с JavaScript / HTML. Пока это еще не так просто.
Тем не менее, вышибающие мозг формулы ведь создавать научились :)
Мне коротко объяснить всю эту штуку сложно, но я попробую.

В общем, если элемент txtCaptcha находится на физической странице Page 2, то и объявить его необходимо в классе Page2. Это вы верно говорите.

Для того, чтобы выяснить из метода Page1.GotoPage2(), отображается ли уже Page2 на экране или ещё нет, мы вызываем Page2.IsDisplayed().

В случае, если Page2.IsDisplayed() вернёт true – ничего делать не нужно. Страница Page2 уже открыта.
В случае false – нам необходимо проделать некоторые действия на странице Page1 для того, чтобы появилась Page2.

У меня есть доклад, в котором я менее скомканным образом рассказываю про эту тему.
Там же есть пример кода взаимодействия между страницами:

blog.zhariy.com/2013/02/atdays-pageobject.html

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

var page1 = new Page1;
var page2 = page1.GoToPage2(); // ①
page2.DoSomeStuff(); // ② 


При условии того, что Page2 не была загружена, строка ② просто упадёт. Если тесты снимают скриншот страницы автоматом при падении, то по нему будет видно, что страница 2 небыла загружена.

Второй вариант, это введение отдельного метода IsDisplayed, как в примере CreateNewAccountPage.cs для каждой страницы.

public override bool IsDisplayed()
{
    return txtCaptcha.Displayed;
}


Смысл метода в том, что он определяет открыта ли страница по некоторому уникальному условию. В примере – это условия отображения контрола txtCaptcha на странице.
Для каждой страницы проверка на существование должно быть уникальным.
Да, это была простая операция. И я догадался что она делает, хоть и были сомнения.

Тем не менее, для достижения самодокументированого кода, необходимо выносить логически завершенные блоки кода в отдельные методы. Тогда код будет рассказывать ЧТО он делает, а не только КАК он это делает.
Это правило должно применяться как к одной строчки кода, так и к 5-ти, например.

Если не хотите множить сущности, то всегда можно добавить комментарий:

// Return if directory is empty
или
// Return ifthere are no .dll files in the directory

А если не хотите добавлять комментарий — тоже не беда. Рано или поздно тот, кто будет читать код, с ним все равно разберется.
Код, сам по себе, объясняет компилятору, КАК он хочет что-то сделать.
Комментарии в коде пишутся для того, чтобы было ясно ЧТО должно быть сделано.

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


Если вы называете переменные не в шахматном стиле, e2 — e4, то это еще не делает ваш код самодокументируемым.

Например, метод MyFrame::loadHandlers(), можно разбить на несколько методов, для каждой магической операции в нем.

Методам — дать хорошие имена, которые говорят, что они делают, а не как.

Вот пример:
Магической операции вроде:
if (!dirHandlers.GetFirst( &sLibName, wxEmptyString, wxDIR_FILES)) return;

Дать имя, которое говорит, что же эта операция таки проверяет:
if (directoryIsEmpty(&sLibName, wxEmptyString, wxDIR_FILES)) return;

Супер, спасибо, Андрей, за Ваш труд
Спасибо, lavice, за качественный перевод. Приятно читать.

Честно говоря, этот текст от автора книги не укладывается у меня в голове. Я рассчитывал, что будет постепенный список того, что можно автоматизировать, несколько советов, по типу автоматизации рутины, может-быть создания своих плагинов для какого-нибудь софта…

Но тут: резкий скачек от “у нас ничего не автоматизировалось” до генерации кода на основе модели. Такой подход, конечно же существует, но я не скажу, что он настолько сильно распространен из-за сложности создания самой модели.
Если брать пример из главы, то мне кажется, легче будет 20 сайтов с корзиной, путь даже на собственном движке, наклепать, чем одну модель все это время разрабатывать.

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

В формуле с рейтами программиста, явно рассматриваются какие-то предельные ситуации: “очень хороший и дорогой”, “дешевый и плохой”.
Будто-бы, посередине ничего нет. Я думаю, за рейт $45, можно вполне найти очень хорошего разработчика на просторах СНГ, так и в Индии (ведь, не все же там индокодят, просто тех, кто индокодит — большее число)
syntax error at 1.pl line 1, near «use Perl or»
Execution of 1.pl aborted due to compilation errors.
К сожалению, мне не удалось воспроизвести проблему с Win7 32-bit + FF 26.
Сама проблема кроется где-то в недрах .NET Framework.

Как последний из вариантов, которые у меня есть,
я прошу вас попробовать установить или обновить полный .NET Framework 4, который можно скачать по следующей ссылке:

www.microsoft.com/en-us/download/details.aspx?id=17718

Возможно, что у вас стоит урезанный Client Profile, в котором нет необходимой библиотеки.
1
23 ...

Information

Rating
Does not participate
Location
Seattle, Washington, США
Date of birth
Registered
Activity