16 Stimmen

Schnellster Weg, um eine Mock-Aktivität für Tests zu erstellen

Ich teste derzeit eine Bibliothek. In bestimmten Klassen muss ich eine Aktivität als Parameter an einige statische Methoden übergeben. Die Bibliothek selbst enthält keine Aktivitäten. Ich muss irgendwie eine Instanz einer Mock-Aktivität erhalten, um sie in jedem einzelnen Methodentest zu verwenden.

Ich habe bereits das Activity-Test-Tutorial und den Abschnitt Testing Fundamentals gelesen. Das meiste davon macht nur Sinn, wenn Sie Aktivitäten testen, die bereits im zu testenden Projekt vorhanden sind. Aber ich brauche nur eine Mock-Aktivität, um Dinge wie das Anzeigen von Dialogen und das Ausführen von kurzen Aufgaben im UI-Thread zu erledigen.

Was ist der schnellste, einfachste Weg, dies zu erreichen? Soll ich die Mock-Aktivität in meinem Testprojekt erstellen und auch XML-Layout-Ressourcen für die Dummy-Benutzeroberfläche bereitstellen?


UPDATE
Da ich keinen Weg gefunden habe, eine Mock-Aktivität automatisch zu erstellen, habe ich beschlossen, sie selbst bereitzustellen. Ich habe im Testprojekt eine Dummy-Aktivität erstellt, die nichts tut, und ein Dummy-Layout über XML bereitgestellt. Dann habe ich meinen Test erstellt, der von ActivityInstrumentationTestCase2 erbt:

    public class LibraryTest extends ActivityInstrumentationTestCase2 {

        public LibraryTest(String name) {
            super(MockActivity.class);
        }

        protected void setUp() throws Exception {
            super.setUp();
        }

        public void testAMethodFromLibrary() {
            fail("Noch nicht implementiert");
        }
    }

Where MockActivity ist die oben erwähnte Mock-Aktivität, die ich in diesem Testprojekt erstellt habe. Allerdings scheint das Android-Testframework Schwierigkeiten zu haben, die Aktivität zu starten, und es zeigt diese Ausnahme an:

        java.lang.RuntimeException: Exception während der Suitenerstellung
        at android.test.suitebuilder.TestSuiteBuilder$FailedToCreateTests.testSuiteConstructionFailed(TestSuiteBuilder.java:239)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
        at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
        at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:520)
        at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1447)
        Caused by: java.lang.NullPointerException: Method name must not be null.
        at java.lang.ClassCache.findMethodByName(ClassCache.java:297)
        at java.lang.Class.getMethod(Class.java:985)
        at android.test.suitebuilder.TestMethod.getAnnotation(TestMethod.java:60)
        at android.test.suitebuilder.annotation.HasMethodAnnotation.apply(HasMethodAnnotation.java:39)
        at android.test.suitebuilder.annotation.HasMethodAnnotation.apply(HasMethodAnnotation.java:30)
        at com.android.internal.util.Predicates$OrPredicate.apply(Predicates.java:106)
        at android.test.suitebuilder.annotation.HasAnnotation.apply(HasAnnotation.java:42)
        at android.test.suitebuilder.annotation.HasAnnotation.apply(HasAnnotation.java:31)
        at com.android.internal.util.Predicates$NotPredicate.apply(Predicates.java:122)
        at android.test.suitebuilder.TestSuiteBuilder.satisfiesAllPredicates(TestSuiteBuilder.java:254)
        at android.test.suitebuilder.TestSuiteBuilder.build(TestSuiteBuilder.java:190)
        at android.test.InstrumentationTestRunner.onCreate(InstrumentationTestRunner.java:373)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4218)
        at android.app.ActivityThread.access$3000(ActivityThread.java:125)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2071)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:123)
        at android.app.ActivityThread.main(ActivityThread.java:4627)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
        at dalvik.system.NativeStart.main(Native Method)

Jetzt bin ich total verloren. Warum ist das so kompliziert? Habe ich den richtigen Weg gewählt? Ich möchte einfach einen Dialog in einer Testmethode starten. Vielleicht hat das Framework Probleme, weil die zu testende Aktivität nicht im Zielprojekt vorhanden ist?

Jede Hilfe hier wäre sehr geschätzt. Ich habe nicht mehr viel Zeit und wenn ich den richtigen Weg nicht finde, müsste ich ein zweites Projekt erstellen, meine Bibliothek dort verwenden und die Mock-Aktivität testen. Das ist eine Menge Code, weil ich eine Methode in einer (nun nicht mehr generischen) Mock-Aktivität hinzufügen müsste, um jede Bibliotheksmethode aufrufen zu können, die ich testen möchte.

9voto

Nicola Gallazzi Punkte 6656

Mit den AndroidX-Bibliotheken können Sie ActivityScenario verwenden. Importieren Sie einfach androidTestImplementation("androidx.test:core:1.5.0") in Ihrer app.gradle-Datei

Dann, in Ihrem Instrumententest, importieren Sie ActivityScenario und starten Sie die Aktivität mit:

import androidx.test.core.app.ActivityScenario

@Test
fun testActivity() {
    ActivityScenario.launch(MainActivity::class.java).onActivity { activity ->
        // do something with your activity instance
    }
}

6voto

Mister Smith Punkte 25957

Gelöst! Das habe ich gemacht:

  • In dem Testprojekt habe ich das Ziel-Paket im Register "Instrumentierung" entfernt und wieder hinzugefügt, wobei es auf das Basispaket des Testprojekts zeigt, in dem die Mock-Aktivität ist.
  • Habe die Zielbibliothek als Android-Bibliothek in meinem Testprojekt hinzugefügt. (Rechtsklick auf das Testprojekt -> Eigenschaften -> Android -> Bibliothek -> die Zielbibliothek hinzugefügt).
  • Die Mock-Aktivität im Manifest des Testprojekts hinzugefügt.
  • Um die oben gepostete Ausnahme zu lösen, habe ich einfach den Testfall-Konstruktor durch diesen ersetzt:

        public LibraryTest() {
            super(MockActivity.class);
        }

Jetzt funktioniert es und ich kann Dialoge erfolgreich starten. Aber bei meinen kurzen Recherchen stieß ich auf Robotium. Diese Bibliothek ist einfach erstaunlich. Zwar war sie für mein ursprüngliches Vorhaben nicht erforderlich, aber ich fand sie sehr nützlich, um Benutzeroberflächen auf automatisierte Weise zu testen. Jetzt habe ich bei jedem setUp-Aufruf eine frisch neue Aktivität erstellt.

0voto

Ajay Deepak Punkte 451

ActivityScenario bietet APIs, um den Lebenszykluszustand einer Aktivität für Tests zu starten und zu steuern. Es funktioniert mit beliebigen Aktivitäten und arbeitet konsistent über verschiedene Versionen des Android-Frameworks hinweg.

val scenario = launchActivity()
scenario.onActivity { activity ->  
// einige Aktionen mit der Aktivität durchführen
}

mit einem benutzerdefinierten Intent

val intent = Intent(ApplicationProvider.getApplicationContext(), MyActivity::class.java)
.putExtra("title", "Testing rules!")
val scenario = launchActivity(intent)
scenario.onActivity { activity ->  
// einige Aktionen mit der Aktivität durchführen
}

ActivityScenarioRule startet die angegebene Aktivität vor dem Test und schließt sie danach. Sie können auf die Szenarioschnittstelle über die Methode getScenario() zugreifen. Sie können Ihre Aktivität manuell in Ihrem Test beenden, dies verursacht keine Probleme, und diese Regel macht in solchen Fällen nach dem Test nichts.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X