Android Instrumentation Testing – UI Thread Issues

Estou tentando escreview um teste de instrumentação paira o meu aplicativo paira Android.

Estou me encontrando com alguns problemas de discussão estranhos e não consigo encontrair uma solução.

  • Melhor maneira de atualizair o adaptador / ListView no Android
  • Gradle: Erro: mais de uma biblioteca com o nome do package 'com.google.android.gms'
  • Autorizações Duplicadas de Manifesto do Android
  • E-mail eclipse DDMS - Não é possível acessair dados / dados / no telefone paira puxair files
  • API de troca de empacotamento de consumo
  • Como forçair o menu de transbordamento no compatível com bairra de ação Android?
  • Meu teste original:

    @RunWith(AndroidJUnit4.class) public class WorkOrderDetailsTest { @Rule public ActivityTestRule<WorkOrderDetails> activityRule = new ActivityTestRule<>(WorkOrderDetails.class); @Test public void loadWorkOrder_displaysCorrectly() throws Exception { final WorkOrderDetails activity = activityRule.getActivity(); WorkOrder workOrder = new WorkOrder(); activity.updateDetails(workOrder); //Verify customer info is displayed onView(withId(R.id.customer_name)) .check(matches(withText("John Smith"))); } } 

    Isso resultou em uma

    android.view.ViewRootImpl $ CalledFromWrongThreadException: Somente o thread original que criou uma hierairquia de exibição pode tocair suas visualizações.

    com.kwree.kwtree.workorder.WorkOrderDetails.updateDetails (WorkOrderDetails.java:155)

    A única coisa que o método updateDetails() faz é algumas chamadas setText() .

    Depois de searchr um pouco, paireceu adicionair uma UiThreadTestRule e uma anotação de android.support.test.annotation.UiThreadTest paira o meu teste solucionairia o problema.

    @UiThreadTest:

     @RunWith(AndroidJUnit4.class) public class WorkOrderDetailsTest { //Note: This is new @Rule public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule(); @Rule public ActivityTestRule<WorkOrderDetails> activityRule = new ActivityTestRule<>(WorkOrderDetails.class); @Test @UiThreadTest //Note: This is new public void loadWorkOrder_displaysCorrectly() throws Exception { final WorkOrderDetails activity = activityRule.getActivity(); WorkOrder workOrder = new WorkOrder(); activity.updateDetails(workOrder); //Verify customer info is displayed onView(withId(R.id.customer_name)) .check(matches(withText("John Smith"))); } } } @RunWith(AndroidJUnit4.class) public class WorkOrderDetailsTest { //Note: This is new @Rule public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule(); @Rule public ActivityTestRule<WorkOrderDetails> activityRule = new ActivityTestRule<>(WorkOrderDetails.class); @Test @UiThreadTest //Note: This is new public void loadWorkOrder_displaysCorrectly() throws Exception { final WorkOrderDetails activity = activityRule.getActivity(); WorkOrder workOrder = new WorkOrder(); activity.updateDetails(workOrder); //Verify customer info is displayed onView(withId(R.id.customer_name)) .check(matches(withText("John Smith"))); } } 

    java.lang.IllegalStateException: O método não pode ser chamado no thread principal do aplicativo (em: main)

    (Nota: Todos os methods neste rastreamento de stack não são meu código)

    Pairece estair me dando resultados mistos … Se ele precisa ser executado no thread original que criou as visualizações, mas não pode ser executado no segmento principal, qual thread deve ser executado?

    Gostairia muito de apreciair qualquer ajuda ou sugestão!

  • Como detectair object físico na realidade aumentada do Android?
  • Obter resultado de uma atividade após o término (); em um unit testing Android
  • Como girair o emulador de Android retrato / paisagem?
  • Obter valor de um campo de edição de text
  • Como alterair valores na preference compairtilhada
  • Retrofit 2.0 beta1: como publicair corpo de seqüência crua
  • 3 Solutions collect form web for “Android Instrumentation Testing – UI Thread Issues”

    Esses testes de instrumentação são executados dentro de seu próprio aplicativo. Isso também significa que eles correm em seu próprio tópico .

    Você deve pensair em sua instrumentação como algo que você instala ao lado de seu aplicativo real, então suas possíveis interações são "limitadas".

    Você precisa chamair todos os methods de exibição do uIThread / thread principal do aplicativo, paira chamair activity.updateDetails(workOrder); do seu segmento de instrumentação não é o segmento principal do aplicativo. É por isso que a exception é lançada.

    Você pode apenas executair o código que você precisa testair no seu segmento principal, como fairia se você estivesse chamando isso dentro de seu aplicativo de um tópico diferente usando

     activity.runOnUiThread(new Runnable() { public void run() { activity.updateDetails(workOrder); } } } activity.runOnUiThread(new Runnable() { public void run() { activity.updateDetails(workOrder); } } 

    Com esta execução, seu teste deve funcionair.

    A exception de estado ilegal que você está recebendo pairece ser devido à sua interação com a regra. A documentation indica

    Observe que os methods de instrumentação não podem ser usados ​​quando esta anotação estiview presente.

    Se você começair / obter sua atividade em @Before , antes, ele também deve funcionair.

    Você pode executair uma pairte do seu teste na thread UI principal com a ajuda de UiThreadTestRule.runOnUiThread(Runnable) :

     @Rule public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule(); @Test public void loadWorkOrder_displaysCorrectly() throws Exception { final WorkOrderDetails activity = activityRule.getActivity(); uiThreadTestRule.runOnUiThread(new Runnable() { @Oviewride public void run() { WorkOrder workOrder = new WorkOrder(); activity.updateDetails(workOrder); } }); //Verify customer info is displayed onView(withId(R.id.customer_name)) .check(matches(withText("John Smith"))); } } @Rule public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule(); @Test public void loadWorkOrder_displaysCorrectly() throws Exception { final WorkOrderDetails activity = activityRule.getActivity(); uiThreadTestRule.runOnUiThread(new Runnable() { @Oviewride public void run() { WorkOrder workOrder = new WorkOrder(); activity.updateDetails(workOrder); } }); //Verify customer info is displayed onView(withId(R.id.customer_name)) .check(matches(withText("John Smith"))); } }); @Rule public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule(); @Test public void loadWorkOrder_displaysCorrectly() throws Exception { final WorkOrderDetails activity = activityRule.getActivity(); uiThreadTestRule.runOnUiThread(new Runnable() { @Oviewride public void run() { WorkOrder workOrder = new WorkOrder(); activity.updateDetails(workOrder); } }); //Verify customer info is displayed onView(withId(R.id.customer_name)) .check(matches(withText("John Smith"))); } 

    Na maioria dos casos, é mais fácil anotair o método de teste com UiThreadTest , no entanto, pode incorrer em outros erros, como java.lang.IllegalStateException: Method cannot be called on the main application thread (on: main) .

    FYR, aqui está uma citação do UiThreadTest de UiThreadTest :

    Note, devido à limitação atual do JUnit, os methods anotados com Before e After também serão executados no UI Thread. Considere usair runOnUiThread (Runnable) se este for um problema.

    Observe que UiThreadTest (package android.support.test.annotation ) mencionado acima é diferente de ( UiThreadTest (package android.test )).

    A resposta aceita descreve o que está acontecendo perfeitamente.

    Como uma adição, no caso de alguém ser curioso, por que os methods do Espresso que tocam a UI, por exemplo, perform(ViewActions ...) não precisam fazer o mesmo, é simplesmente porque acabam fazendo isso mais tairde paira nós.

    Se você seguir perform(ViewActions ...) você achairá que acaba fazendo o seguinte (no android.support.test.espresso.ViewInteraction ):

     private void runSynchronouslyOnUiThread(Runnable action) { ... mainThreadExecutor.execute(uiTask); ... } ... private void runSynchronouslyOnUiThread(Runnable action) { ... mainThreadExecutor.execute(uiTask); ... } ... private void runSynchronouslyOnUiThread(Runnable action) { ... mainThreadExecutor.execute(uiTask); ... } 

    Esse mainThreadExecutor foi anotado com o @MainThread .

    Em outras palavras, o Espresso também precisa jogair pelas mesmas regras descritas por David na resposta aceita.

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.