2015-11-10 11 views
6

Pracuję nad przeniesieniem projektu do testów espresso obecnie. Przeczytałem kilka dokumentów i przestrzegałem podanych praktyk, aby rozpocząć.Testy Android Espresso Intents test losowo kończą się niepowodzeniem z `` init() musi zostać wywołana przed użyciem tej metody``

Wszystko działa dobrze, jednak jeśli chodzi o test dotyczący intencji, wynik jest dziwny.

W większości przypadków testy zakończyły się na moim Macu, ale zawiodły w systemie Windows mojego kolegi (nie wszystkie testy zakończą się niepowodzeniem) z komunikatem o błędzie java.lang.IllegalStateException: init() must be called prior to using this method.

Dość dziwnie, jeśli uruchomimy test debugowania w Androidzie Studio, przepuścimy kod krok po kroku, przechodzi.

Oto kod testu:

@RunWith(AndroidJUnit4.class) 
@LargeTest 
public class MainActivityTest { 

    @Rule public IntentsTestRule<MainActivity> mRule = new IntentsTestRule<>(MainActivity.class, true, false); 

    AccountManager accountManager; 
    MainActivity activity; 


    private void buildLoginStatus() throws AuthenticatorException { 
    DanteApp app = (DanteApp) InstrumentationRegistry.getTargetContext().getApplicationContext(); 
    accountManager = app.getDanteAppComponent().accountManager(); 

    DoctorModel doctorModel = AccountMocker.mockDoctorModel(); 
    accountManager.save(doctorModel.doctor); 
    accountManager.setAccessToken(doctorModel.access_token, false); 
    } 

    @Before public void before() throws Exception { 
    buildLoginStatus(); 

    // must login 
    assertThat(accountManager.hasAuthenticated(), is(true)); 

    activity = mRule.launchActivity(null); 
    // block all of the outer intents 
    intending(not(isInternal())).respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, null)); 
    } 

    @After public void tearDown() throws Exception { 
    accountManager.delete(); 
    } 

    // failed 
    @Test public void testViewDisplay() throws Exception { 

    // check tabhost is displayed 
    onView(withClassName(equalTo(TabHost.class.getName()))).check(matches(isDisplayed())); 

    // check toolbar is displayed 
    onView(withClassName(equalTo(ToolBar.class.getName()))).check(matches(isDisplayed())); 
    } 

    // passed 
    @Test public void testCallServiceHotline() throws Exception { 
    // switch to the account tab layout 
    onView(withChild(withText(R.string.account))).perform(click()); 
    // click account menu to make a service call 
    onView(withId(R.id.contact)).perform(click()); 

    // check call start expectly 
    intended(allOf(
     not(isInternal()), 
     hasAction(Intent.ACTION_DIAL), 
     hasData(Uri.parse("tel:" + activity.getString(R.string.call_service))) 
    )); 
    } 


    // failed 
    @Test public void testOpenSettingsUI() throws Exception { 
    // stub all internal intents 
    Intents.intending(isInternal()) 
     .respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, null)); 

    onView(withChild(withText(R.string.account))).perform(click()); 
    onView(withId(R.id.setting)).perform(click()); 

    // check open settings activity successfully 
    intended(anyOf(
     hasComponent(SettingActivity.class.getName()) 
    )); 
    } 
} 

Wersja testowania biblioteki (prawie wszystkie zależności są aktualne i używamy oba urządzenia fizyki i emulator do testowania):

  • zasada: 0,4 0,1
  • płoza: 0.4.1
  • espresso * 2.2.1
  • Support- *: 23.1.0

Każdy pomysł zasługuje na uznanie. Dzięki!

Odpowiedz

14

dwa rozwiązania:

  1. Zastosowanie ActivityTestRule zamiast IntentsTestRule a następnie w @Before i @After ręcznie wywołać Intents.init() i Intents.release() odpowiednio.
  2. Napisz niestandardową metodę IntentTestRule i przesuń przedActivityLaunched(), aby uwzględnić logikę AccountManager. Użyj opcji AfterActivityFinished dla bieżącej logiki @After. Umożliwi to również użycie domyślnego konstruktora IntentTestRule. (Preferowane rozwiązanie)

Jak się dlaczego tak się dzieje.

„W końcu na niepowiązanych uwaga, należy zachować ostrożność podczas korzystania z nowego IntentsTestRule To nie inicjuje, Intents.init(), aż po uruchomieniu działania (afterActivityLaunched()). " - Shameless plug to my own post (halfway down helpful visual)

myślę używasz w wyścigu, gdzie w swojej metodzie @Before jesteś wykonującego launchActivity(), a następnie espresso próbuje wykonać intending(not(isInternal())).respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, null)); przed swoją działalność jest faktycznie tworzone, co oznacza afterActivityLaunched() nie nazywa, które oznacza także, że nie jest Intents.init(), awaria!

Mam nadzieję, że to pomoże.

0

IntentsTestRule pochodzi z ActivityTestRule i powinien zarządzać dla Ciebie Intents.init() i Intents.release().

Jednak w moim przypadku IntentsTestRule nie działa poprawnie.Wracam więc do ActivityTestRule i zadzwonię pod numer Intents.init() przed i Intents.release() po teście, który wysłał intencję.

Aby uzyskać więcej informacji, zobacz ten reference.

Powiązane problemy