Jak przetestować aplikację na Androida w wielu działaniach?

80

Tworzymy złożoną aplikację na Androida składającą się z wielu ekranów i przepływów pracy rozłożonych na wiele działań. Nasze przepływy pracy są podobne do tego, co możesz zobaczyć na bankomacie banku, na przykład istnieje Activitymożliwość zalogowania się w tym przejściu do menu głównego, Activityktóre może przejść do innych czynności w zależności od wyborów użytkownika.

Ponieważ mamy tak wiele przepływów pracy, musimy stworzyć automatyczne testy, które obejmują wiele działań, abyśmy mogli przetestować przepływ pracy od końca do końca. Na przykład, korzystając z przykładu bankomatu, chcielibyśmy wprowadzić poprawny PIN, zweryfikować, czy wysyła nas do menu głównego, wybrać wypłatę gotówki, sprawdzić, czy jesteśmy na ekranie wypłaty gotówki itp. z powrotem w menu głównym lub „wylogowany”.

Bawiliśmy się testowymi interfejsami API, które są dostarczane z Androidem (np. ActivityInstrumentationTestCase2), A także z Positronem , ale żaden z nich nie wydaje się być zdolny do testowania poza granicami jednego Activityi chociaż możemy znaleźć w tych narzędziach pewne narzędzia do niektórych testów jednostkowych, wygrali nie spełnia naszych potrzeb w zakresie scenariuszy testowania, które obejmują wiele działań.

Jesteśmy otwarci na framework xUnit, skrypty, rejestratory / odtwarzanie GUI itp. I będziemy wdzięczni za każdą radę.

Pojedynczy strzał
źródło
2
Począwszy od Androida 4.1, dostępna jest teraz nowa platforma testowa dla Androida, która umożliwia testowanie w różnych działaniach, a nawet w całym systemie: developer.android.com/tools/testing/testing_ui.html
Christopher Orr
1
Robotium również będzie odpowiadał tej potrzebie i tylko w kilku liniach.
Dori

Odpowiedzi:

65

Czuję się trochę niezręcznie, odpowiadając na moje własne pytanie o nagrodę, ale oto jest ...

Szukałem tego wysoko i nisko i nie mogę uwierzyć, że nigdzie nie ma opublikowanej odpowiedzi. Podszedłem bardzo blisko. Zdecydowanie mogę teraz uruchamiać testy, które obejmują działania, ale wydaje się, że w mojej implementacji występują pewne problemy z synchronizacją, przez co testy nie zawsze kończą się rzetelnie. To jedyny znany mi przykład tego, że pomyślnie testuje wiele działań. Miejmy nadzieję, że moje wyodrębnienie i anonimizacja tego nie spowodowało błędów. To jest uproszczony test, w którym wpisuję nazwę użytkownika i hasło w czynności logowania, a następnie obserwuję, jak odpowiedni komunikat powitalny jest wyświetlany w innym działaniu „powitalnym”:

package com.mycompany;

import android.app.*;
import android.content.*;
import android.test.*;
import android.test.suitebuilder.annotation.*;
import android.util.*;
import android.view.*;
import android.widget.*;

import static org.hamcrest.core.Is.*;
import static org.hamcrest.core.IsNull.*;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.*;
import static com.mycompany.R.id.*;

public class LoginTests extends InstrumentationTestCase {

   @MediumTest
   public void testAValidUserCanLogIn() {

      Instrumentation instrumentation = getInstrumentation();

      // Register we are interested in the authentication activiry...
      Instrumentation.ActivityMonitor monitor = instrumentation.addMonitor(AuthenticateActivity.class.getName(), null, false);

      // Start the authentication activity as the first activity...
      Intent intent = new Intent(Intent.ACTION_MAIN);
      intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      intent.setClassName(instrumentation.getTargetContext(), AuthenticateActivity.class.getName());
      instrumentation.startActivitySync(intent);

      // Wait for it to start...
      Activity currentActivity = getInstrumentation().waitForMonitorWithTimeout(monitor, 5);
      assertThat(currentActivity, is(notNullValue()));

      // Type into the username field...
      View currentView = currentActivity.findViewById(username_field);
      assertThat(currentView, is(notNullValue()));
      assertThat(currentView, instanceOf(EditText.class));
      TouchUtils.clickView(this, currentView);
      instrumentation.sendStringSync("MyUsername");

      // Type into the password field...
      currentView = currentActivity.findViewById(password_field);
      assertThat(currentView, is(notNullValue()));
      assertThat(currentView, instanceOf(EditText.class));
      TouchUtils.clickView(this, currentView);
      instrumentation.sendStringSync("MyPassword");

      // Register we are interested in the welcome activity...
      // this has to be done before we do something that will send us to that
      // activity...
      instrumentation.removeMonitor(monitor);
      monitor = instrumentation.addMonitor(WelcomeActivity.class.getName(), null, false);

      // Click the login button...
      currentView = currentActivity.findViewById(login_button;
      assertThat(currentView, is(notNullValue()));
      assertThat(currentView, instanceOf(Button.class));
      TouchUtils.clickView(this, currentView);

      // Wait for the welcome page to start...
      currentActivity = getInstrumentation().waitForMonitorWithTimeout(monitor, 5);
      assertThat(currentActivity, is(notNullValue()));

      // Make sure we are logged in...
      currentView = currentActivity.findViewById(welcome_message);
      assertThat(currentView, is(notNullValue()));
      assertThat(currentView, instanceOf(TextView.class));
      assertThat(((TextView)currentView).getText().toString(), is("Welcome, MyUsername!"));
   }
}

Ten kod jest oczywiście niezbyt czytelny. Właściwie rozpakowałem go do prostej biblioteki z interfejsem API podobnym do angielskiego, więc mogę po prostu powiedzieć takie rzeczy:

type("myUsername").intoThe(username_field);
click(login_button);

Przetestowałem do głębokości około 4 czynności i jestem zadowolony, że to podejście działa, chociaż, jak powiedziałem, wydaje się, że czasami występuje problem z synchronizacją, którego nie do końca rozgryzłem. Nadal jestem zainteresowany innymi sposobami testowania różnych działań.

Pojedynczy strzał
źródło
3
Możesz spróbować dodać adnotację FlakyTest, aby automatycznie powtórzyć test, gdy problemy z synchronizacją powodują jego niepowodzenie. Właściwie nie jest to rozwiązanie, ale realne obejście w niektórych sytuacjach.
Carl Manaster,
Dzięki za napisanie tego! Do testów szukałem czegoś z funkcjonalnością monitorów aktywności. Po prostu nie mogłem ich znaleźć.
Peter Ajtai
O ile wiem, niczego, co zrobiłeś powyżej, nie można zrobić przy użyciuActivityInstrumentationTestCase2
ericn,
dowolny pomysł, pod jakim warunkiem, 'getInstrumentation (). waitForIdleSync ();' wejdzie w nieskończoną pętlę? Na płycie procesora z systemem Android 4.4.2_r2 mam do czynienia z tym problemem podczas wykonywania testu CTS.
ArunJTS
Myślę, że mój syn @ pajato1 znalazł i naprawił twój problem z synchronizacją. Jego poprawka rozwiązała mój problem. Oto, co powiedział: „Właśnie zauważyłem w javadoc, że Instrumentation.startActivitySync () blokuje, dopóki nowe działanie nie będzie gotowe, a następnie zwróciło, więc wygląda na to, że Monitor nie był konieczny. Usunięcie go dowiodło, że to prawda. Mój Teoria jest taka, że ​​Monitor powodował ponowne uruchamianie działania utworzonego przez startActivitySync () w niektórych przypadkach z powodu wyścigu. Spędziłem trochę czasu na czytaniu kodu źródłowego Androida, ale nic nie wyskoczyło na mnie jako przyczyna stanu wyścigu. "
pajato0
22

Spójrz na Robotium platformę testową
typu open source stworzoną w celu znacznego przyspieszenia i ułatwienia automatycznego testowania czarnoskrzynkowych aplikacji na Androida w porównaniu z tym, co jest możliwe dzięki natychmiastowym testom instrumentacji Androida”.

Strona internetowa: http://www.robotium.org/
Źródło: http://github.com/jayway/robotium

Należy pamiętać, że projekt Robotium jest obsługiwany przez firmę, w której pracuję

Jonas Söderström
źródło
cześć, czy jest do tego narzędzie do nagrywania? Sprawdziłem wiele stron internetowych i znalazłem testdroid, który zapisuje skrypty i uruchamia go. Niestety nie jest to oprogramowanie freeware, czy znasz jakieś darmowe oprogramowanie, które zajmuje się nagrywaniem?
thndrkiss
@thndrkiss: Nie znam żadnego takiego narzędzia. Jeśli zadasz pytanie na forum Robotium, prawdopodobnie uzyskasz lepszą odpowiedź.
Jonas Söderström
2
Robotium ratuje życie. Dzięki temu twój test będzie niezwykle łatwy do napisania (w zasadzie mówisz do niego prostym angielskim: kliknij to, naciśnij przycisk Wstecz itp.) Możesz przetestować wszystko, ale nie musisz znać drobnych szczegółów. Ma co najmniej dwie główne zalety: możesz testować aplikacje, których nie masz kodu źródłowego, i opiera się na interfejsie użytkownika, który czyni go bardzo niezawodnym (zmieniasz kontrolery / modele znacznie bardziej niż widoki ...)
tiktak
8

Zawsze możesz użyć Robotium. Obsługuje testowanie czarnej skrzynki, podobnie jak Selenium, ale dla Androida. Znajdziesz go na Robotium.org

Renas
źródło
1
Ostatnim razem, gdy sprawdzałem, że Robotium nie może być używany w działaniach. Czy to zostało już naprawione? stackoverflow.com/questions/3840034/…
user77115
3
Zawsze działało w przypadku działań, o ile należą one do tego samego procesu.
Renas
4

Jestem zaskoczony, że nikt nie wspomniał o niektórych wiodących zautomatyzowanych narzędziach do testowania funkcjonalnego . W porównaniu z Robotium nie wymagają one pisania kodu Java.

MonkeyTalk : narzędzie open source wspierane przez firmę Gorilla Logic. Zalety: zapewnia nagrywanie, a także język skryptowy wyższego poziomu, łatwiejszy dla użytkowników nietechnicznych, i jest wieloplatformowy (w tym iOS). Biorąc pod uwagę te korzyści jako wymagania, uznaliśmy, że jest to najlepsze rozwiązanie. Umożliwia także dostosowanie wykraczające poza to, co można zrobić w ich języku skryptowym za pomocą JavaScript.

Calabash-Android : narzędzie typu open source dla funkcji w stylu ogórka. Zalety: pisz funkcje w języku Gherkin, który jest czytelnym dla biznesu językiem specyficznym dla domeny, który pozwala opisywać zachowanie oprogramowania bez szczegółowego opisu sposobu implementacji tego zachowania. Podobne, ale nie dokładne wsparcie jest dostępne dla iOS w Cucumber-Ios . Możliwości nagrywania nie są tak dobre, ponieważ dają wyjście binarne.

Kilka innych odniesień:

  • Oto kilka dodatkowych porównań między Robotium, Monkeytalk i Calabash. Wspomina TestDroid jako inną możliwość.
  • Ten blog wspomina o powyższym oraz NativeDriver i Bot-bot.
John Lehmann
źródło
3

Stworzyłem narzędzie do nagrywania i odtwarzania dla Androida i udostępniłem je na GitHub . Jest łatwy w konfiguracji i obsłudze, nie wymaga programowania, działa na prawdziwych urządzeniach (które nie muszą być rootowane) i automatycznie zapisuje zrzuty ekranu podczas odtwarzania testów.

Brian Kyckelhahn
źródło
To wygląda obiecująco. Dla tych, którzy nie widzą sensu: wydaje się, że jest to całkiem dobre rozwiązanie do testowania gestów (stukanie, przeciąganie i inne rzeczy)
tiktak
3

Przede wszystkim użyj „ActivityInstrumentationTestCase2”, a nie „InstrumentationTestCase” jako klasy bazowej. Używam Robotium i rutynowo testuję wiele działań. Zauważyłem, że muszę określić aktywność logowania jako typ ogólny (i argument klasy dla konstruktora).

Konstruktor „ActivityInstrumentationTestCase2” ignoruje argument pakietu i nie wymaga go. Konstruktor, który przyjmuje pakiet, jest przestarzały.

Z Javadocs: "ActivityInstrumentationTestCase2 (String pkg, Class activityClass) Ten konstruktor jest przestarzały. Zamiast tego użyj ActivityInstrumentationTestCase2 (Class)"

Użycie zalecanej klasy bazowej umożliwia platformie obsługę określonych schematów, takich jak rozpoczęcie działania. Odbywa się to przez wywołanie metody „getActivity ()”, jeśli to konieczne.

Lew Bloch
źródło
3

Okazało się to przydatne z kilkoma modyfikacjami. Po pierwsze getInstrumentation().waitForIdleSync()wyleczy łuszczenie się, o którym mówi SingleShot, a także InstrumentationTestCasema lauchActivityfunkcję, która może zastąpić początkowe linie aktywności.

kaczka
źródło
2

możesz to zrobić w ten sposób, aby uniknąć zsynchronizowania czasu oczekiwania na płatek:

final Button btnLogin = (Button) getActivity().findViewById(R.id.button);
Instrumentation instrumentation = getInstrumentation();

// Register we are interested in the authentication activity...
Instrumentation.ActivityMonitor aMonitor = 
        instrumentation.addMonitor(mynextActivity.class.getName(), null, false);

getInstrumentation().runOnMainSync(new Runnable() {
         public void run() {
             btnLogin.performClick();
         }
     });

getInstrumentation().waitForIdleSync();

//check if we got at least one hit on the new activity
assertTrue(getInstrumentation().checkMonitorHit(aMonitor, 1)); 
j2emanue
źródło
1

Pracuję prawie nad tym samym i prawdopodobnie pójdę z wariacją na temat zaakceptowanej odpowiedzi na to pytanie, ale natknąłem się na Calculuon ( gitHub ) podczas moich poszukiwań rozwiązania.

Peter Ajtai
źródło
0

Osobiście go nie używałem, ale wygląda na to, że ApplicationTestCase może być tym, czego szukasz.

Eric
źródło
Niestety nie ma przykładów wskazujących na to, że tak jest.
SingleShot,
Tak, wygląda na to, że masz rację ... nazwa oszukała. Nie mogę tego rozgryźć. Najlepszym podejściem, jakie mam do tej pory, jest użycie ActivityUnitTestCase pozytonu, aby sprawdzić, czy następna aktywność jest uruchomiona, ale to nie pomaga w tworzeniu spójnych historii. Alternatywnie, InstrumentationTestCase.launchActivity może pozwolić na rozpoczęcie dowolnej liczby działań, ale wciąż próbuję dowiedzieć się, co jest instrumentacją.
Eric
0

Czy zaakceptowane podejście będzie działać w przypadku różnych działań z różnych aplikacji, podpisanych różnymi certyfikatami? Jeśli nie, Robotium to najlepszy sposób na przetestowanie działań w ramach tej samej aplikacji.

user643154
źródło
0

Istnieje inny sposób wykonywania wielu czynności przy użyciu klasy ActivityInstrumentation .. To normalny scenariusz automatyzacji ... Najpierw skup się na dowolnym obiekcie, a następnie wyślij klucz Prosty jak ten przykładowy kod

button.requestFocus();
sendKeys(KeyEvent.KEYCODE_ENTER);

Jedyną rzeczą jest zrozumienie, że każde wywołanie API nam pomoże.

Sandeep
źródło
0

Ta odpowiedź jest oparta na zaakceptowanej odpowiedzi, ale zmodyfikowana w celu rozwiązania problemu z synchronizacją, który dla mnie stał się spójny po dodaniu około pół tuzina testów. @ pajato1 otrzymuje uznanie za rozwiązanie problemu z synchronizacją, jak podano w komentarzach zaakceptowanej odpowiedzi.

/**
 * Creates a test Activity for a given fully qualified test class name.
 *
 * @param fullyQualifiedClassName The fully qualified name of test activity class.
 *
 * @return The test activity object or null if it could not be located.
 */
protected AbstractTestActivity getTestActivity(final String fullyQualifiedClassName) {
    AbstractTestActivity result = null;

    // Register our interest in the given activity and start it.
    Log.d(TAG, String.format("Running test (%s) with main class: %s.", getName(), fullyQualifiedClassName));
    instrumentation = getInstrumentation();

    Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setClassName(instrumentation.getTargetContext(), fullyQualifiedClassName);
    // Wait for the activity to finish starting
    Activity activity = instrumentation.startActivitySync(intent);

    // Perform basic sanity checks.
    assertTrue("The activity is null!  Aborting.", activity != null);
    String format = "The test activity is of the wrong type (%s).";
    assertTrue(String.format(format, activity.getClass().getName()), activity.getClass().getName().equals(fullyQualifiedClassName));
    result = (AbstractTestActivity) activity;

    return result;
}
pajato0
źródło
0

Wypróbuj testowanie narzędzia Monkey

Krok 1:

otwórz terminal Android Studio (Narzędzia-> otwórz terminal)

Krok 2:

Aby użyć małpy, otwórz wiersz polecenia i po prostu przejdź do następującego katalogu.

 export PATH=$PATH:/home/adt-bundle-linux-x86-20140702/sdk/platform-tools

Krok 3:

dodaj to polecenie małpy do terminala i naciśnij enter.

zobacz magię swojego emulatora.

adb shell monkey -p com.example.yourpackage -v 500

500 - jest to liczba częstotliwości lub liczba zdarzeń do wysłania do testów.

możesz zmienić tę liczbę ...

Więcej informacji,

http://www.tutorialspoint.com/android/android_testing.htm

http://androidtesting.blogspot.in/2012/04/android-testing-with-monkey-tool.html

Ranjith Kumar
źródło
Osoby tracące głosy muszą podać powód ich odrzucenia ... to działa kod ... i oficjalna metoda testowania. Jeśli jakikolwiek błąd, jestem gotów poprawić swoją odpowiedź ...
Ranjith Kumar,