ActivityInstrumentationTestCase2 И тестовите случаи на Robotium висят, докато не се натисне back/home на емулатора, ЗАЩО?

Разработвам приложение за графичен калкулатор с едно действие. (Android API 10) Оформлението е доста сложно с 40+ бутона, заемащи долната половина на екрана и оформление на рамка като горната част на екрана. Оформлението на рамката е подклас в "ScreenFrame", който държи "екрана" на калкулатора. ВСЕКИ изглед/група изгледи, които се показват в ScreenFrame, са персонализирани изгледи/групи изгледи, които показват изчисленията, които потребителят извършва. Помислете за графичен калкулатор на TI, където целият израз може да се види със символи за операции...

Пишех JUnit тестове, най-вече подкласове на AndroidTestCase, защото имам нужда само от контекст, за да тествам огромна част от кода, а не цялата рамка на дейността. Въпреки това стигам до точката, в която бих искал да започна да пиша функционални тестови случаи и някои части от приложението изискват цялата рамка на дейността, за да работят.

Ето го проблемът, който ме озадачи напълно. Първо ще покажа кода за тестовия случай

public class CommandTest extends ActivityInstrumentationTestCase2<Calculator> {

    private Calculator _calculator;

    public CommandTest(){
        super(Calculator.class);
    }

    @Override
    protected void setUp() throws Exception {
        setActivityInitialTouchMode(true);
        _calculator = getActivity();
        super.setUp();
    }

    @Override
    protected void tearDown() throws Exception {
        super.tearDown();
        _calculator.finish(); // doesn't make a difference if this line is there or not
    }

    public void testCircleBadSyntax1() {
        _calculator.runOnUiThread(new Runnable() {
            @Override public void run() {
                Button twoButton = (Button) _calculator.findViewById(R.id.twoButton);
                twoButton.performClick();
                Button addButton = (Button) _calculator.findViewById(R.id.addButton);
                addButton.performClick();
                Button nineButton = (Button) _calculator.findViewById(R.id.nineButton);
                nineButton.performClick();
                Button enterButton = (Button) _calculator.findViewById(R.id.equalsButton);
                enterButton.performClick();
             }
        });
        Instrumentation inst = getInstrumentation();
        inst.waitForIdleSync();

        _calculator.runOnUiThread(new Runnable() {
             @Override public void run() {
                 ScreenFrame screenFrame = (ScreenFrame) _calculator.findViewById(R.id.screenFrame);
                 assertNotNull(screenFrame);
                 AnswerSymbolGroup answer = screenFrame.getLastAnswer();
                 INumber number = answer.getNumberAnswer();
                 assertEquals(number.getValueInt(), 11); 
            }
    });
        _calculator.finish();
    }
}

Току-що ви показах как настройвам всичко и един примерен тестов случай по-горе. Всички случаи на тестове са подобни и това, което се тества, не е проблемът... Основният проблем е, че когато стартирам теста през eclipse, тестът просто виси на първия екземпляр на тестов случай за неопределено време (опитах се да го оставя за докато само за да видя и просто стоеше там със синя стрелка на първия случай за 45+ минути). Изключително странната част е, че когато натисна или бутона HOME, или бутона за връщане назад на емулатора, тестът се изпълнява. И дава правилния отговор. Не виждате никакви промени на екрана или други неща, които трябва да видите при натискане на бутони, но тестовият случай работи както трябва. което означава, че преминава или се проваля в зависимост от кода, който тествам. След това програмата за тестване остава на следващия тест, докато не натисна отново бутона за връщане или начало.

Това не е работещо решение. Бих искал да имам десет до двадесет случая (понякога много повече) в тестов файл и бих искал всички да се изпълняват успешно, без да се налага да натискам нищо на емулатора, особено след като имам настройка на Jenkins CI, която използвам за всички други тестове, които имам без проблем.

Така че реших, че рамка като robotium за тези видове тестове ще бъде по-подходяща за справяне с тези видове тестове.

Имам същия проблем с robotium. Когато стартирам тестов случай на robotium с показване на началния екран на емулатора, тестовият случай стартира, извежда екрана на калкулатора и след това виси за неопределено време. Когато натисна бутона за връщане назад и след това отворя отново приложението, тестовият случай започва отначало и продължава да работи както трябва, което означава, че преминава, ако кодът, който тества, е правилен, докато се проваля, ако не. Вие обаче можете да видите подходящите промени с кутиите на роботиума. Например, ако даденият тест беше коригиран да използва соло променлива за щракване върху бутоните и нищо от нещата на runOnUiThreads, две ще се появи на екрана след натискане на бутона две, след това плюс, девет и единадесет след въвеждане е натиснат. При следващия тестов случай се случва същото, виси безкрайно. Когато щракна назад или начало, след което отворя отново приложението, тестът ще продължи. Всеки тестов случай трябва да повтарям този процес. Не съм опитвал да изпълнявам тези тестове в моя Jenkins модул (все още работя как да стартирам безглавен тест на роботиум).

Бях объркан от това от доста дни и не смятам, че трябва да губя повече време, опитвайки се да го разбера. Някой друг изпитвал ли е подобно поведение.

Обикновено ненавиждам използването на дебъгера за намиране на грешки, защото смятам, че отнема много повече време от писането на тестове и регистриране на подходящия изход в LOGCAT. Въпреки това се опитах да стартирам програмата за отстраняване на грешки в тази ситуация, за да разбера къде висят нещата. Знам, че тестът виси на линията getActivity()... Стигам до точката в програмата за отстраняване на грешки, където правя цикъл в главния цикъл. Методите onCreate(), onStart() и onResume() са завършени и целият екран е видим, но след като това се случи, той виси, докато не натисна бутона за връщане назад или бутона за начало.

Наистина бих искал да разбера защо се случва това и да мога да изпълнявам множество тестови случаи последователно.

/** Добавено след като дойдоха първите ДВА отговора **/ Към първия отговор вече се опитах да поставя activity.finish() в метода tearDown(), няма значение...

За втория отговор, опитах всяко възможно изброяване къде да поставя super.setUp() и super.tearDown() в рамките на тестовете setUp и tearDown(), без да ги включвам като една от опциите.

Опитах се да премина през метода getActivity() на дебъгера по-задълбочено и мога да кажа, че кодът се забива в класа Instrumentation в метода startActivitySync(Intent intent).

на ред 391 getTargetContext().startActivity(intent) се изпълнява и след това се намира на следващата част на ключалката за синхронизиране ...

getTargetContext().startActivity(intent);

do{
    try{
        mSync.wait();
    } catch(InterruptedException e){
    }
}while(mWaitingActivities.contains(aw));

return aw.activity;

person phriendtj    schedule 21.11.2013    source източник
comment
Възможно ли е безкрайно повтаряща се анимация на изглед да причини зависването, а не?   -  person phriendtj    schedule 22.11.2013
comment
Имам същия проблем. получихте ли решение?   -  person ericyoung    schedule 21.05.2014


Отговори (3)


Във вашия метод tearDown трябва да извикате _calculator.finish();

За тестове, които отварят множество дейности, robotium има удобен метод за завършване на всички: solo.finishOpenedActivities();

person Dave C    schedule 21.11.2013
comment
Не показах това в кода, който публикувах, но извиквам тези методи в метода tearDown() и има само една дейност в приложението ми.... - person phriendtj; 21.11.2013

Не съм сигурен дали ще ви помогне, но трябва да извикате super.setUp(); в началото на метода setUp и super.tearDown(); в края на метода tearDown. Можете също да опитате да ги премахнете.

Между другото извикването на setActivityInitialTouchMode(false); няма смисъл, защото:

Ако не извикате това, режимът на докосване ще бъде false. Ако извикате това, след като активността ви е стартирана, това няма да има ефект.

person maszter    schedule 21.11.2013

Имах подобен проблем. Мога да разреша проблема си, като поставя метода setAdapter() в класа AsyncTask.

person Leonardo    schedule 10.12.2013