UPDATE 2/13/2012: Zaakceptowano odpowiedź, wyjaśniłem, że to zachowanie jest błędem, i zauważyłem, że wydaje się, że zniknęło na emulatorach lepiej niż wersja 1.6, co sprawia, że nie jest to problem dla większości z nas. Obejście problemu polega po prostu na zapętleniu/uśpieniu aż do getContext(). Funkcja getApplicationContext() zwraca wartość inną niż null. END UPDATEDlaczego metoda AndroidTestCase.getContext(). GetApplicationContext() zwraca wartość null?
Zgodnie z Android.app.Application javadoc, zdefiniowałem singleton (nazywany Database), że wszystkie moje aktywności uzyskują dostęp do stanów i trwałych danych, a Database.getDatabase (Kontekst) pobiera kontekst aplikacji przez kontekst. getApplicationContext(). Ta konfiguracja działa tak, jak jest reklamowana, gdy działania przekazują się do getDatabase (kontekst), ale kiedy uruchamiam test jednostki z AndroidTestCase, wywołanie getApplicationContext() często zwraca wartość null, chociaż im dłuższy test, tym częściej zwraca wartość inną niż null wartość.
Poniższy kod odtwarza wartość null w obrębie AndroidTestCase - singleton nie jest konieczny do demonstracji.
Najpierw, aby rejestrować wiadomości z aplikacjami, w testowanej aplikacji zdefiniowałem MyApp i dodałem ją do manifestu.
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Log.i("MYAPP", "this=" + this);
Log.i("MYAPP", "getAppCtx()=" + getApplicationContext());
}
}
Następnie zdefiniowałem przypadek testowy zgłosić na AndroidTestCase.getContext (4-krotnie), oddzielone przez niektórych śpi a getSharedPreferences() połączenia:
public class DatabaseTest extends AndroidTestCase {
public void test_exploreContext() {
exploreContexts("XPLORE1");
getContext().getSharedPreferences("foo", Context.MODE_PRIVATE);
exploreContexts("XPLORE2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
exploreContexts("XPLORE3");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
exploreContexts("XPLORE4");
}
public void exploreContexts(String tag) {
Context testContext = getContext();
Log.i(tag, "testCtx=" + testContext +
" pkg=" + testContext.getApplicationInfo().packageName);
Log.i(tag, "testContext.getAppCtx()=" + testContext.getApplicationContext());
try {
Context appContext = testContext.createPackageContext("com.foo.android", 0);
ApplicationInfo appInfo = appContext.getApplicationInfo();
Log.i(tag, "appContext=" + appContext +
" pkg=" + appContext.getApplicationInfo().packageName);
Log.i(tag, "appContext.getAppCtx()=" + appContext.getApplicationContext());
} catch (NameNotFoundException e) {
Log.i(tag, "Can't get app context.");
}
}
}
I to jest kawał Otrzymany logcat (1,6 emulatora SDK11 WinXP poprzez Eclipse)
INFO/TestRunner(465): started: test_exploreContext(test.foo.android.DatabaseTest)
INFO/XPLORE1(465): [email protected] pkg=com.foo.android
INFO/XPLORE1(465): testContext.getAppCtx()=null
INFO/XPLORE1(465): [email protected] pkg=com.foo.android
INFO/XPLORE1(465): appContext.getAppCtx()=null
INFO/XPLORE2(465): [email protected] pkg=com.foo.android
INFO/XPLORE2(465): testContext.getAppCtx()=null
INFO/XPLORE2(465): [email protected] pkg=com.foo.android
INFO/XPLORE2(465): appContext.getAppCtx()=null
INFO/MYAPP(465): [email protected]
INFO/MYAPP(465): getAppCtx()[email protected]
INFO/XPLORE3(465): [email protected] pkg=com.foo.android
INFO/XPLORE3(465): testContext.getAppCtx()[email protected]
INFO/XPLORE3(465): [email protected] pkg=com.foo.android
INFO/XPLORE3(465): appContext.getAppCtx()[email protected]
INFO/XPLORE4(465): [email protected] pkg=com.foo.android
INFO/XPLORE4(465): testContext.getAppCtx()[email protected]
INFO/XPLORE4(465): [email protected] pkg=com.foo.android
INFO/XPLORE4(465): appContext.getAppCtx()[email protected]
INFO/TestRunner(465): finished: test_exploreContext(test.foo.android.DatabaseTest)
Należy zauważyć, że getApplicationContext() zwrócone zerowy na chwilę, po czym zaczął powrocie wystąpienie MojaApl. Nie byłem w stanie uzyskać dokładnie takich samych rezultatów w różnych przebiegach tego testu (tak skończyłem w 4 iteracjach, śpi i to wywołanie getSharedPreferences(), aby spróbować uruchomić aplikację).
Fragment wiadomości LogCat powyżej wydawał się najbardziej odpowiedni, ale cały LogCat dla tego pojedynczego przebiegu tego pojedynczego testu był interesujący. Android uruchomił 4 AndroidRuntimes; ten kawałek powyżej był z czwartego. Co ciekawe, 3rd Runtime wyświetlane komunikaty wskazujące, że instancja inną instancję MojaApl w ID procesu 447:
INFO/TestRunner(447): started: test_exploreContext(test.foo.android.DatabaseTest)
INFO/MYAPP(447): [email protected]
INFO/MYAPP(447): getAppCtx()[email protected]
INFO/TestRunner(447): finished: test_exploreContext(test.foo.android.DatabaseTest)
Przypuszczam, że (447) komunikaty TestRunner pochodzą z raportów wątku testowym rodzic na swoich dzieci w procesie 465 Pozostaje jednak pytanie: dlaczego Android uruchamia AndroidTestCase, zanim jego kontekst zostanie poprawnie podłączony do instancji aplikacji?
Obejście: Jeden z moich testów wydawało się uniknąć null większość czasu, gdy zadzwoniłem getContext().getSharedPreferences("anyname", Context.MODE_PRIVATE).edit().clear().commit();
pierwszy, więc idę z tym.
BTW: Jeśli odpowiedź brzmi: "to błąd Androida, dlaczego go nie zarchiwizujesz, do cholery, dlaczego go nie naprawisz?" wtedy byłbym gotów zrobić jedno i drugie. Nie zrobiłem jeszcze kroku, by być filantem lub płatnikiem błędów - może to dobry czas.
Zauważyłem też dziwne zachowanie w AndroidTestCase. Zazwyczaj każdy test jest uruchamiany wiele razy, ale tylko raz raportuje do Eclipse. Na przykład czasami otrzymuję wyjątki 'Nullpointer' w' onDestroy', podczas gdy wszystkie pola instancji zostały poprawnie zainicjowane w 'onCreate'. Możesz to przetestować poprzez wstawienie punktu przerwania w 'onDestroy' i zobaczenie, że wykonanie przerwało się tam co najmniej 4 razy, podczas gdy test był uruchamiany tylko raz. – siamii
Mam ten sam problem na emulatorze Androida 4.0.4, w którym czasami znajdował się ApplicationContext, a czasami nie. Twoje obejście problemu, dopóki się nie pojawi, wydaje się działać. – Ralf
Pojawia się także dla mnie podczas testów na emulatorze HAX z SDK 10. W przeciwnym razie wygląda na to, że błędu nie można już odtworzyć. – Snicolas