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 Activity
możliwość zalogowania się w tym przejściu do menu głównego, Activity
któ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 Activity
i 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ę.
źródło
Odpowiedzi:
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ń.
źródło
ActivityInstrumentationTestCase2
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ę
źródło
Zawsze możesz użyć Robotium. Obsługuje testowanie czarnej skrzynki, podobnie jak Selenium, ale dla Androida. Znajdziesz go na Robotium.org
źródło
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ń:
źródło
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.
źródło
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.
źródło
Okazało się to przydatne z kilkoma modyfikacjami. Po pierwsze
getInstrumentation().waitForIdleSync()
wyleczy łuszczenie się, o którym mówi SingleShot, a takżeInstrumentationTestCase
malauchActivity
funkcję, która może zastąpić początkowe linie aktywności.źródło
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));
źródło
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.
źródło
Osobiście go nie używałem, ale wygląda na to, że ApplicationTestCase może być tym, czego szukasz.
źródło
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.
źródło
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.
źródło
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; }
źródło
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
źródło