Wie können wir in Robolectric auf den Kontext einer Anwendung zugreifen?

112

Eigentlich muss ich eine Antwort auf einen API-Aufruf bekommen, dafür brauchte ich Context.

user1667968
quelle

Antworten:

218

Aktualisieren.

Verwenden Sie einfach für Version 1.x und 2.x:

Robolectric.application;

Und für Version 3.x:

RuntimeEnvironment.application;

Und für Version 4.x:

  • zu deiner build.gradleDatei hinzufügen :

    testImplementation 'androidx.test:core:1.0.0'
    
  • Rufen Sie den Kontext ab mit:

    ApplicationProvider.getApplicationContext()
    
Eugen Martynov
quelle
11
Haben Sie @RunWith (RobolectricTestRunner.class) für Ihre Tests verwendet?
Eugen Martynov
4
Ja .. ich fügte hinzu ... aber es gibt immer noch null zurück
user1667968
1
Ich habe alles getan, was du erwähnt hast und bekomme immer noch null. Kann ich sonst noch etwas vermissen?
Moises Jimenez
13
Stellen Sie außerdem sicher, dass Sie keinen RuntimeEnvironment.applicationstatischen Code verwenden (wie mit Anmerkungen versehene Methoden @BeforeClass), da Robolectric zu diesem Zeitpunkt wahrscheinlich nicht initialisiert wird und der Wert lautet null.
Sfera
1
Dies führt auch dazu, dass die Anwendung zwischen den Tests blutet. Dies ist möglicherweise nicht wünschenswert
Chris,
26

Sie können verwenden

RuntimeEnvironment.application
rds
quelle
4
In RoboElectric 3.0 existiert Roboelectric.application nicht mehr, daher ist dies wahrscheinlich die beste Antwort
Kenyee
19

Benutze das:

Robolectric.application
Xian
quelle
16

Hinzufügen

testImplementation "androidx.test:core-ktx:${deps.testrunner}"

Und benutze:

private val app = ApplicationProvider.getApplicationContext()
John
quelle
import androidx.test.core.app.ApplicationProvider
Glückshandler
val appContext = ApplicationProvider.getApplicationContext <Context> ()
Glückshandler
2
Dies ist die richtige Antwort mit dem neuesten Robolectric. Andere hier erwähnte Methoden sind veraltet oder werden entfernt.
Gabor
7

Für den neuesten Robolectric 4.3 ab 2019 `

ShadowApplication.getInstance ()

`und

Roboletric.application

sind beide beraubt. Also benutze ich

Context context = RuntimeEnvironment.systemContext;

Kontext zu bekommen.

The_Martian
quelle
5

Um den Anwendungskontext zu erhalten, müssen Sie Folgendes tun:

  1. annotieren Sie @RunWith (RobolectricTestRunner.class)
  2. RuntimeEnvironment.application.getApplicationContext ()
user1390616
quelle
2

Dies funktioniert bei mir mit Robolectric 3.5.1: ShadowApplication.getInstance().applicationContext

Farrukh Najmi
quelle
Beachten Sie, dass die Version 4.0 diese Methode anscheinend entfernt. Besser bleiben RuntimeEnvironment.applicationoder RuntimeEnvironment.application.getApplicationContext()wenn es für dich funktioniert.
Qix
2

Ab Release 4.0-alpha-3 am 21. Juli wurden sie entfernt ShadowApplication.getApplicationContext() . Halten Sie sich RuntimeEnvironment.application.getApplicationContext()für alle mit Anmerkungen versehenen Tests an @RunWith(RobolectricTestRunner::class).

Abgesehen davon enthält der aktuelle Leitfaden ein Beispiel für das Abrufen von Zeichenfolgenressourcen mithilfe von:

final Context context = RuntimeEnvironment.application;

(Beachten Sie, dass die Javadocs für RuntimeEnvironmentund ShadowApplicationderzeit die Nicht-Alpha-Version 3.x widerspiegeln.)

qix
quelle
2

Fügen Sie zunächst Folgendes zu Ihrem hinzu build.gradle:

testImplementation 'androidx.test:core:1.2.0'

dann benutze:

ApplicationProvider.getApplicationContext() as Application

Dougie
quelle
2

In einigen Fällen benötigen Sie möglicherweise den Kontext Ihrer App anstelle des Robolectris-Standardkontexts. Zum Beispiel, wenn Sie Ihren Paketnamen erhalten möchten. Standardmäßig gibt Robolectric Ihren org.robolectric.defaultPaketnamen zurück. Gehen Sie wie folgt vor, um Ihren tatsächlichen Paketnamen zu erhalten:

build.gradle

testImplementation 'org.robolectric:robolectric:4.2.1'

Ihre Testklasse:

@RunWith(RobolectricTestRunner.class)
@Config( manifest="AndroidManifest.xml")
public class FooTest {

@Test
public void fooTestWithPackageName(){
    Context context = ApplicationProvider.getApplicationContext();
    System.out.println("My Real Package Name: " + context.getPackageName());
}

}

Stellen Sie sicher, dass in Ihrem Arbeitsverzeichnis Run / Debug Configurations Folgendes festgelegt ist: $ MODULE_DIR $ Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

Kirill Karmazin
quelle
1

Es ist sicherer , zu verwenden , Robolectric.getShadowApplication()anstatt mit Robolectric.applicationdirekt.

drspaceboo
quelle
Was aber, wenn ich auf einige benutzerdefinierte Eigenschaften meiner benutzerdefinierten Anwendung zugreifen muss? Es scheint, dass ich das reale Objekt nicht aus der Schattenanwendung erhalten kann.
Denis Kniazhev
@DenisKniazhev Entschuldigung, das kann ich nicht für Sie beantworten. Kurz nachdem wir angefangen hatten, Robolectric zu verwenden, haben wir angefangen, Travis als unser CI zu verwenden, und sie spielen nicht gut. Ich vermute, dass Sie es entweder in Ihre Anwendung umwandeln können oder einen benutzerdefinierten Runner erstellen müssen, um auf diese Weise darauf zugreifen zu können.
Viel
Danke, für jetzt habe ich mich gerade gehaltenRobolectric.application
Denis Kniazhev
6
Robolectric.getShadowApplication () ist nicht verfügbar
IgorGanapolsky
1

Stimmen Sie den Antworten von @EugenMartynov und @rds zu ....

Ein kurzes Beispiel finden Sie bei Volley-Marshmallow-Release

in NetworkImageViewTest.java

// mNIV = new NetworkImageView(Robolectric.application); mNIV = new NetworkImageView(RuntimeEnvironment.application);

Der Volley-Link ist unter https://android.googlesource.com/platform/frameworks/volley/+/marshmallow-release verfügbar

Sie müssen Abhängigkeiten im Volley-Modul in Android Studio hinzufügen als:

dependencies { testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:1.10.19' testCompile 'org.robolectric:robolectric:3.1.2' }

Bhuro
quelle
1

In Ihrem Fall sollten Sie sich bewusst sein, was Sie tatsächlich testen. Manchmal ist es ein Zeichen dafür, dass Ihr Code möglicherweise überarbeitet werden muss, wenn Probleme mit nicht testbarem Code oder scheinbar nicht testbarem Code auftreten.

Für eine API-Aufrufantwort möchten Sie möglicherweise den API-Aufruf selbst nicht testen. Es ist möglicherweise nicht erforderlich zu testen, ob es möglich ist, Informationen von einem beliebigen Webdienst zu senden / zu empfangen, sondern dass Ihr Code Ihre Antwort in einem erwarteten Zustand verarbeitet und verarbeitet.

In diesem Fall ist es möglicherweise besser, den Code, den Sie testen möchten, umzugestalten. Brechen Sie das Parsen / Behandeln von Antworten in eine andere Klasse auf, die eine einfache akzeptiert, Stringund führen Sie Ihre Tests für diese Klasse durch, indem Sie Antworten auf Beispielzeichenfolgen einfügen.

Dies folgt mehr oder weniger den Vorstellungen von Single Responsibility und Dependency Inversion ( S und D in SOLID ).

Grego
quelle
1

Ok, ich weiß also, dass viele andere diese Antwort schon einmal gesagt haben und möglicherweise bereits veraltet sind

    when(mockApplication.getApplicationContext()).thenReturn(RuntimeEnvironment.application);
    when(mockApplication.getFilesDir()).thenReturn(RuntimeEnvironment.application.getFilesDir());

    sharedPref = RuntimeEnvironment.application.getSharedPreferences(KEY_MY_PREF, Context.MODE_PRIVATE);
    sut = new BundleManagerImpl(mockApplication,
            processHtmlBundle, resultListener, sharedPref);

Ich habe null bekommen, weil der when () Teil NACH der Sut-Initialisierung war. Es könnte einigen von Ihnen helfen.

auch ich habe die

@RunWith(CustomRobolectricTestRunner.class)
@Config(constants = BuildConfig.class)

zu Beginn des Unterrichts

Ebenfalls

 when(mockApplication.getApplicationContext()).thenReturn(RuntimeEnvironment.application.getApplicationContext()); works
Karoly
quelle