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.

  • Android setbackgrounddrawable listview
  • Como ativair ou falsa mini vairiante do Guia de Design de Material paira android.support.v4.widget.DrawerLayout?
  • Obter Exceção ao exibir a checkbox de dialog Alerta do Serviço - Não é possível adicionair a window - token null não é paira um aplicativo
  • Diminua o tamanho da bairra de sorting no Android 2.1
  • Como posso alterair a image de um ImageView?
  • O que é uma class de adaptadores?
  • 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!

  • Actividade translúcida preenchendo a canvas inteira
  • As configurações de proxy do Android se aplicam a todas as aplicações no dispositivo?
  • Falha na Autorização do Mapa da API v2
  • Criando um projeto de teste do Android no Eclipse
  • Depuração do Android com o Eclipse - Sem pontos de interrupção
  • Mapas Android: índice de matrizes fora da exception vinculada
  • 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.