Pull to refresh
2
0
AlekseiM@m_aleksei

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

Send message

iOS медленнее соглашусь, Android скорость такая что пытается тапать кнопку на экране, пока она еще появляется. Решается отрубанием анимации. Это кстати и для iOS помогает немного.

У нас 900+ тестов, 25 тел (12 iOS + 13 Андроид). По ночам бегают около 700 (1400 на две платформы) при релизах все. У нас много долгих тестов (например 2 платежа в тесте с заполнением кучи полей). Вообщем вполне сносно все 1800 (900 на обе платформы) бегут за 3.5 часа Андроид и немного дольше iOS.

C фермами типа browserstack заморачиваться не стали (наша ферма окупается за 3 месяца если выбирать планы с 20+ параллельными тел против самой дешевой фермы).

Молодцы!

У нас примерно тоже только Appium + Java + TestNG + Allure.

Из плюсов на Java можно писать умопомрачительные локаторы

@iOSXCUITFindBy(id = "PT5PlanSelectorView")
@iOSXCUITFindAll(value = {
  @iOSXCUITBy(id = "bottomButton"),
  @iOSXCUITBy(id = "otherButton")}, priority = 1)
@AndroidFindBy(id = "aftv_button_text")
private WebElement choosePlanButton;
// or
@iOSXCUITFindBy(iOSNsPredicate = "type == 'XCUIElementTypeButton' AND (label == 'Next' OR label == 'View your spending')")
@AndroidFindAll(value = {
     @AndroidBy(id = "a193_continue_button"), // old
     @AndroidBy(id = "pb_mm1") // new
})
private WebElement viewSpendingButton;

пример теста:

        login(getCustomer())
                .tapBurgerButton().isBurgerMenuPageLoaded()
                .tapMyPlanButton()
                .isMyPlanPageLoaded();

        // check plan monthly fee
        resultDB = myApp().myPlanPage().getPlanMonthlyFee();
        expectedBD = PlanFees.getMonthly(tier, false);
        getSoftAssert().assertEquals(resultDB, expectedBD, "MyPlan(): Monthly fee NOT correct");

        // check free withdrawal amount left
        resultDB = myApp().myPlanPage().getFreeATMAndTopUps(getCustomer());
        expectedBD = AtmAndCashTopUps.valueOf(tier.name()).getFreeAtmAndTopUp();
        getSoftAssert().assertEquals(resultDB, expectedBD, "Free withdrawal amount NOT correct'");

Видео всех тестов вставляем в отчет тоже.

Поделитесь для сравнения количеством тестов и скоростью выполнения. Спасибо.

аааааа. ну это прямо основы математики которые в банке должен знать каждый!

ЗЫ Про Excel или расчеты на калькуляторе пару значений это вы точно сказали. Отвык народ работать руками.

что то не понятно... почему сразу не использовать?

BigDecimal prc = new BigDecimal(10.75).setScale(2, RoundingMode.HALF_UP);
BigDecimal coef = new BigDecimal(365*100).setScale(0, RoundingMode.HALF_UP);

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

Я бы порекомендовал добавлять описание ошибки. Вот у нас я автомачу мобильные тесты один, а юзают их все манульщики. И писать 2 <> 3 не совсем ясно, что такое 2 и почему 3. Ошибки должен понимать человек кто видит продукт первый раз.

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

1) Step это от Allure - https://docs.qameta.io/allure/#_testng

2) это не НА каждый, а ПОСЛЕ каждого. нету смысла искать мгновенно элементы другой страницы

3) Аппиум аннотации типа @iOSXCUITBy, @AndroidBy и т.д. (их много) также имеют ожидания. Не помню по умолчанию, я заменяю его на свое 20сек. Ну а когда мне нужно короче (часто проверить что нету элемента) то уменьшаю и потом восстанавливаю. Пример

    @Step("Check 'Green button' loaded {sec}")
    public boolean isGreenButtonLoaded(int sec) {
        Logger.log("sec: '" + sec + "'");
        setLookTiming(sec);
        return super.isLoaded(greenButton);
    }

где isLoaded проверяет за МАКС время есть или нет + восстанавливает значение по умолчанию. Понятно что максимум искать будет только если нету.

Привет.

1) по скроллу я написал гайд -> http://appium.io/docs/en/writing-running-appium/tutorial/swipe-tutorial/ . только немного уже устарел сам тап. правильнее уже использовать http://appium.io/docs/en/commands/interactions/actions/

2) все tap(el), setInput(el, value), getText(el)... со всех страниц ведут в 1 единственную функцию для каждого действия. например все tap ведут одну функцию. Это супер удобно. Во первых можно поправить в одном месте КАК тап делаем и везде меняется. Во вторых после ACTION действий типа тап, которые приводят к изменениям удобно добавить маленькую паузу (я использую 150ms). Это значительно повышает надежность.

3) как видно из примера оборачивание дает также название действия для Allure отчета + логирования. это все крайне полезно особенно если бегут много тестов одновременно.

пример в Allure как видно

все действия понятны любому QA

плюс в обертке мы пишем человекочитаемые ошибки типа:

т.е. это не ХЗ какой-то элемент со стактрейсом который мануальщикам ничего не говорит, а понятная ошибка.

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

Ну и видео дополняет картину.

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

апка
  .скринТакой
  .тапКнопкиТакой
  .проверьТакойТоСкринЗагрузился
  .вПолеТакоеВвведи("какой то текст")
  .тапКнопкиТакой
  .проверьТакойТоСкринЗагрузился
  ...

по статик импорту не понял вопроса. не вижу его. вот пример всех импортов с какого-то теста:

package tests.debitcard.addSecondaryCardOrder;

import base.enums.AccountType;
import core.testrail.TestRailCase;
import core.utils.enums.Currency;
import core.utils.enums.MAccountType;
import customers.Customer;
import customers.CustomerForGenerating;
import io.qameta.allure.Epic;
import io.qameta.allure.Feature;
import io.qameta.allure.Severity;
import io.qameta.allure.SeverityLevel;
import org.testng.annotations.Test;
import tests.addAccount.BaseAddAccount;
import tests.debitcard.BaseDebitCard;
import tests.debitcard.CardQueryMethods;

а вот пример импортов с PageObject (тут только логирование из статиков):

package pages.payments;

import base.BasePage;
import base.Page;
import core.utils.logging.Logger;
import io.appium.java_client.MobileBy;
import io.appium.java_client.pagefactory.*;
import io.qameta.allure.Step;
import org.openqa.selenium.WebElement;
import org.testng.Assert;
import pages.home.HomePage;
import pages.pots.PotViewPage;

import static core.utils.logging.Logger.createAssertionLog;


public class PaymentSentPage extends BasePage {

Kaspresso представил удобную обертку, зато за Аппиумом поддержка всех платформ.

За что мне нравится Аппиум:

  • поддержка всех платформ. пишем тест 1 раз

  • поддержка умопомрачительных возможностей поиска элементов

  • видео тоже есть

  • у нас 900 тестов под обе платформы (iOS + Android)

  • кол-во автотестеров сейчас 1 (было 2. второй ушел на другой проект сейчас)

  • запускают тесты все мануальщики

  • ноль проблем со стабильностью. у нас больше проблема в стабильности сервера из-за наличия многих ThirdParty сервисов.

Пример поиска элементов прям с кода:

    @iOSXCUITFindAll(value = {
            @iOSXCUITBy(id = "CARDADRConfirmationView"), // new
            @iOSXCUITBy(id = "I44S4ConfirmAddressView"),
            @iOSXCUITBy(id = "ADR3ConfirmAddressOnboardingView"),
            @iOSXCUITBy(id = "I56DebitCardNotArrivedView"), // business
            @iOSXCUITBy(id = "BIZ14ChooseAddressView") // business
    })
    @iOSXCUITFindAll(value = {
            @iOSXCUITBy(id = "orderAnother"), // business
            @iOSXCUITBy(id = "bottomButton"), // business
            @iOSXCUITBy(id = "confirmButton") // old ?
    }, priority = 1)
    @AndroidFindAll(value = {
            @AndroidBy(id = "btn_base_bottom_sheet_primary"),
            @AndroidBy(id = "btn_confirm_address"), // business
            @AndroidBy(id = "btn_nux2s0s1_confirm"), // confirm address after login with EUR account only
    })
    private WebElement confirmAddressButton;

PS ах да. я бы посоветовал код писать чуть красивее типа -> (сек прям с кода...)

xxxApp()
	.onboarding().mobilePhonePage()
	.verifyAndSetCountryCode(expectedCode, country)
	.setPhone(customer.getPhone())
	.tapVerifyNumberButton()
	.tapMyNumberIsCorrect()
	.enterVerificationCode(customer.getPhone(), smsVerificationTokenOld);

где например:

    @Step("Tap 'Verify Number' button")
    public MobilePhonePage tapVerifyNumberButton() {
        Logger.log();
        Assert.assertTrue(tap(verifyNumberButton), createAssertionLog("FAILED"));
        return this;
    }

Мне симпатизирует ваша точка зрения, но иного выхода как блокада ресурсов я не вижу.

Вот вы как предлагаете действовать в данном случае?

Неправда. Мы недавно джуниора из Пакистана вытащили. Уже почти месяц у нас. Всем довольны. Толковый, быстро учится, минимальный надзор.

Сейчас конечно больше кандидатов толковых с России едет и стало временно проще.

Многие знакомые годами народ у нас в Эстонии найти не может. Слишком много стартапов у нас и бегают по кругу все подымая зарплаты и плюшки.

oi пропустил.

java + maven + testNG + appium + allure reporter.

А вы аппелируйте к тому, что тесты НЕ должны все все покрывать. Ибо система которая тестирует любое приложение на 100% всегда сложнее самого приложения.

Кому надо, чтобы затраты на тестирования были больше создания? Есть конечно варианты: космос, медицина, системы управления - если ваша апка к ним не относится, вы не должны покрывать все случаи. Это дорого.

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

Ну а поправить идшки в форме это вообще не проблема. Вот если меняется флоу, то сложнее. Тут все зависит как написаны тесты, поправить в 1 месте не проблема.

Вначале я сам ставил идшки в ios коде. Через пол года, когда авто тесты стали находить быстро регресии, програмисты сами стали помогать и сохранять идшки.

Сейчас у нас 870 тестов мобильных тестов под ios и столько же под android.

Представьте как обслуживать это? Так вот у нас всего 2 авто тестера на эти мобильные, апи (сейчас очень много его), веб и т.д.

Все зависит от того как написано, так и обслуживаться будет.

все верно! я видел толпы автоматчиков, работу которых никто в фирме не понимает, кроме них самих.

1) любые тесты должны быть такими, чтобы их запускали ВСЕ члены команды. Мануальщики в первую очередь, программеры во вторую, а сами автоматчики в последнюю.

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

3) наличие видео крайне повышает комфортность и полезность (хотя вначале так не кажется пока не начнешь пользоваться). Ясно, что с АПИ так не получится, а вот web + mobile видео обязательно давно.

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

это проблема кривых рук автотестеров (чаще) и окружения (реже).

у крупных городах не у всех дома есть возможность ставить на зардку на ночь. замена батареи решает кучи проблем:

  • батарея меняется за 1-3 мин

  • легко заменить 50 - 70 -100 - 150 kW (как пожелаешь на станции)

  • легко утилизировать - не надо разбирать машину

  • нет проблем с гарантией на батарею

А у нас был похожий опыт!

Я начал проставлять айдишки в приложении iOS сам. Позднее девелоперы увидев помогли сделать генерацию всех айдишек автоматически если билд не релиз или не продакшн.

пример:

<XCUIElementTypeOther type="XCUIElementTypeOther" enabled="true" visible="false" x="0" y="111" width="375" height="56" name="generated_MultipleBalanceView">
<XCUIElementTypeOther type="XCUIElementTypeOther" enabled="true" visible="false" x="0" y="111" width="375" height="56" name="generated_UIStackView">
<XCUIElementTypeOther type="XCUIElementTypeOther" enabled="true" visible="false" x="95" y="111" width="185" height="56" name="generated_UIStackView">
<XCUIElementTypeOther type="XCUIElementTypeOther" enabled="true" visible="false" x="95" y="111" width="107" height="56" name="generated_AnimatingBalanceLabel">
<XCUIElementTypeStaticText type="XCUIElementTypeStaticText" enabled="true" visible="false" x="95" y="111" width="107" height="56" name="balanceLabel" label="£0,00" value="£0,00">

таким образом автоматом были доступны мне (я на аппиуме пишу) хоть какие-то ид чтобы писать не зализая в код iOS.

сейчас я уже не часто меняю сгенеренную идшку на свою (тут в примере - `balanceLabel`).

метод уже прижился в нескольких фирмах. реализация правда сделана чуть по разному.

но в обоих меняю ид (если надо) крайне удобно добавив '.id("myID")' к любому элементу:

let saveAmountLabel = Label().id("saveAmountLabel").style(.amount)

вот такой опыт.

Кстати по поводу одиноковых элементов в Аппиуме прекрасные варианты как искать типа:

    // chain: generated_UINavigationBar -> generated_UINavigationBar
    @iOSXCUITFindBys(value = {
            @iOSXCUITBy(id = "generated_UINavigationBar"),
            @iOSXCUITBy(id = "generated__UIButtonBarButton")
    })
    
    // all: X1View or X2View
    @iOSXCUITFindAll(value = {
            @iOSXCUITBy(id = "X1View"),
            @iOSXCUITBy(id = "X2View")
    })
    
    // all chain all: any X1View or X2View -> any X3View or X4View
    @iOSXCUITFindAll(value = {
            @iOSXCUITBy(id = "X1View")
            @iOSXCUITBy(id = "X2View")
    })
    @iOSXCUITFindAll(value = {
            @iOSXCUITBy(id = "X3View"),
            @iOSXCUITBy(id = "X4View")
    }, priority = 1)
    
    // classChain: get second 'generated_LinkButton' then inside first 'XCUIElementTypeStaticText'
    @iOSXCUITFindBy(iOSClassChain = "**/XCUIElementTypeButton[`name == \"generated_LinkButton\"`][2]/**/XCUIElementTypeStaticText")
    
    // predicate class 'XCUIElementTypeImage' with name contains 'cardActiveImage_'
    @iOSXCUITFindBy(iOSNsPredicate = "type == 'XCUIElementTypeImage' AND name CONTAINS[cd] 'cardActiveImage_'")
    
    // now any combination of all above :-)

Так они регулярно каждую неделю новый слепок в staging делают.

кстати идею подсказали! сделал ребуут телефонов джобу на 7 утра. все одной проблемой меньше.

Information

Rating
Does not participate
Location
Таллин, Эстония, Эстония
Registered
Activity