2016-02-26 4 views
3

Я работал над простым примером использования SeekBar, и у меня возникают проблемы с тем, чтобы мой тест Espresso работал. Когда я запускаю тесты, я могу увидеть движение SeekBar на экране эмулятора, но, по-видимому, он не вызывает OnSeekBarChangeListener, потому что TextView не изменяет значение («Hello World!» - это начальное значение). Если я запустил программу и проверил ее вручную, TextView обновится, как я ожидаю.Тест на поисковую систему, не вызывающий OnSeekBarChangeListener

Основная программа:

package edu.eku.styere.seekbar; 

import android.app.Activity; 
import android.os.Bundle; 
import android.os.Handler; 
import android.view.View; 
import android.widget.Button; 
import android.widget.TextView; 
import android.widget.SeekBar; 
import android.widget.SeekBar.OnSeekBarChangeListener; 

public class MainActivity extends Activity { 
    private int cur_progress = 0; 
    boolean running = false; 
    final int SEEK_MAX = 100; 
    final int DELAY_MILLIS = 200; 
    private TextView mProgressLabel; 
    private SeekBar mProgressBar; 

    // message handler 
    private Handler mHandler = new Handler(); 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     // fetch items 
     mProgressLabel = (TextView) findViewById(R.id.progress_text); 
     mProgressBar = (SeekBar) findViewById(R.id.progress_seekbar); 

     Button startButton = (Button) findViewById(R.id.btn_start); 
     startButton.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View view) { 
       // start the timer/progresss bar 
       cur_progress = 0; 
       running = true; 
       // start messages 
       mHandler.postDelayed(mUpdateTimeTask, DELAY_MILLIS); 
      } 
     }); 

     // respond to changes in the seek bar by the user 
     mProgressBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { 
      public void onProgressChanged(SeekBar sb, int progress, boolean fromUser) { 
       // user change or from us? 
       if (fromUser) { 
        // user changed the bar, so get a new value 
        cur_progress = progress; 

        // update the text box 
        mProgressLabel.setText("progress: " + cur_progress); 

        mHandler.removeCallbacks(mUpdateTimeTask); 
        if (running) 
         mHandler.postDelayed(mUpdateTimeTask, DELAY_MILLIS); 
       } 
      } 

      // need to have these, but not using them here 
      public void onStartTrackingTouch(SeekBar seekBar) { 
       // TODO Auto-generated method stub 
      } 

      public void onStopTrackingTouch(SeekBar seekBar) { 
       // TODO Auto-generated method stub 
      } 
     }); 
    } 

    // the runnable object that corresponds to our timer 
    private Runnable mUpdateTimeTask = new Runnable() { 
     public void run() { 
      // done? 
      if (cur_progress >= SEEK_MAX) { 
       // stop everything 
       mHandler.removeCallbacks(mUpdateTimeTask); 
       running = false; 
       return; 
      } 
      // update the progress 
      cur_progress++; 
      // update the text box 
      mProgressLabel.setText("progress: " + cur_progress); 
      // update the seek bar (does not cause onChange event) 
      mProgressBar.setProgress(cur_progress); 

      //do this again 
      mHandler.postDelayed(this, DELAY_MILLIS); 
     } 
    }; // mUpdateTimeTask 
} 

Код проверки:

package edu.eku.styere.seekbar; 

import android.app.Instrumentation; 
import android.os.SystemClock; 
import android.support.test.InstrumentationRegistry; 
import android.support.test.espresso.UiController; 
import android.support.test.espresso.ViewAction; 
import android.support.test.espresso.action.CoordinatesProvider; 
import android.support.test.espresso.action.GeneralSwipeAction; 
import android.support.test.espresso.action.Press; 
import android.support.test.espresso.action.Swipe; 
import android.support.test.espresso.matcher.ViewMatchers; 
import android.support.test.rule.ActivityTestRule; 
import android.support.test.runner.AndroidJUnit4; 
import android.test.InstrumentationTestCase; 
import android.view.MotionEvent; 
import android.view.View; 
import android.widget.SeekBar; 

import org.hamcrest.Matcher; 
import org.junit.Rule; 
import org.junit.Test; 
import org.junit.runner.RunWith; 

import java.util.Random; 

import static android.support.test.espresso.Espresso.onView; 
import static android.support.test.espresso.action.ViewActions.click; 
import static android.support.test.espresso.assertion.ViewAssertions.matches; 
import static android.support.test.espresso.matcher.ViewMatchers.withId; 
import static android.support.test.espresso.matcher.ViewMatchers.withText; 

@RunWith(AndroidJUnit4.class) 
public class MainActivityTest { 
    //Random rng = new Random(); 

    @Rule 
    public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class); 

    @Test 
    public void moveSeekBar() { 
     onView(withId(R.id.progress_seekbar)).perform(setProgress(35)); 

     // Check that the text was changed 
     onView(withId(R.id.progress_text)) 
       .check(matches(withText("progress: " + 35))); 
    } 

    public static ViewAction setProgress(final int progress) { 
     return new ViewAction() { 
      @Override 
      public void perform(UiController uiController, View view) { 
       SeekBar seekBar = (SeekBar) view; 
       seekBar.setProgress(progress); 
      } 
      @Override 
      public String getDescription() { 
       return "Set a progress on a SeekBar"; 
      } 
      @Override 
      public Matcher<View> getConstraints() { 
       return ViewMatchers.isAssignableFrom(SeekBar.class); 
      } 
     }; 
    } 
} 

Результат неудачного теста:

android.support.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: 'with text: is "progress: 35"' doesn't match the selected view. 
Expected: with text: is "progress: 35" 
Got: "TextView{id=2131165185, res-name=progress_text, visibility=VISIBLE, width=480, height=29, 
has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, 
is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, 
root-is-layout-requested=false, has-input-connection=false, x=0.0, y=72.0, 
text=Hello world!, input-type=0, ime-target=false, has-links=false}" 

... 
+0

Добавьте небольшую задержку 0,5 сек для обеспечения того, чтобы тест не прерывался из-за состояния гонки или чего-то еще. – Shark

+0

Не думал о состоянии гонки, но даже 5-секундная задержка ничего не меняет :( –

ответ

0

Похоже на провал утверждение, где, кажется, как будто выход идентичный («прогресс: 35»). Тем не менее, это может привести к ошибке утверждения с < 4> не равно < 4> когда одна строка, а одна - int. Это может быть связано с тем, как продвигается продвижение вперед/оценивается.

Редактировать: (извините слишком низкая репутация, чтобы комментировать). Является ли это «fromUser» логическим? Я использую некоторые очень похожий код, который работает, но я не проверить, что логическое ...

+0

Нет, если вы посмотрите внимательно на «Got ...», вы в конечном итоге доберетесь до того места, где обнаружите, что TextView все еще содержит «Hello World!». Кроме того, в 5-секундном тестировании задержки я мог видеть на экране, что TextView не изменился. –

4

Ну после того, как еще некоторые работы мне удалось создать решение моей проблемы, на основе GenericClickAction:

package edu.eku.styere.seekbar; 

import android.support.test.espresso.ViewAction; 
import android.support.test.espresso.action.CoordinatesProvider; 
import android.support.test.espresso.action.GeneralClickAction; 
import android.support.test.espresso.action.Press; 
import android.support.test.espresso.action.Tap; 
import android.support.test.rule.ActivityTestRule; 
import android.support.test.runner.AndroidJUnit4; 
import android.view.View; 
import android.widget.SeekBar; 

import org.junit.Rule; 
import org.junit.Test; 
import org.junit.runner.RunWith; 

import java.util.Random; 

import static android.support.test.espresso.Espresso.onView; 
import static android.support.test.espresso.assertion.ViewAssertions.matches; 
import static android.support.test.espresso.matcher.ViewMatchers.withId; 
import static android.support.test.espresso.matcher.ViewMatchers.withText; 

@RunWith(AndroidJUnit4.class) 
public class MainActivityTest { 
    Random rng = new Random(); 

    @Rule 
    public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class); 

    @Test 
    public void moveSeekBar() { 
     int cur_progress; 

     // do an initial move in case the first random number is 0 
     // -- if it didn't move, the OnSeekBarChangeListener isn't called 
     onView(withId(R.id.progress_seekbar)).perform(clickSeekBar(25)); 

     // try 10 random locations 
     for(int i=0; i<10; i++) { 
      cur_progress = rng.nextInt(101);   // 0..100 

      // move it to a random location 
      onView(withId(R.id.progress_seekbar)).perform(clickSeekBar(cur_progress)); 

      try { 
       Thread.sleep(1000); 
      } catch (Exception e) { 
       // do nothing 
      } 
      // Check that the text was changed 
      onView(withId(R.id.progress_text)) 
        .check(matches(withText("progress: " + cur_progress))); 
     } 
    } 

    public static ViewAction clickSeekBar(final int pos){ 
     return new GeneralClickAction(
       Tap.SINGLE, 
       new CoordinatesProvider() { 
        @Override 
        public float[] calculateCoordinates(View view) { 
         SeekBar seekBar = (SeekBar) view; 
         final int[] screenPos = new int[2]; 
         seekBar.getLocationOnScreen(screenPos); 

         // get the width of the actual bar area 
         // by removing padding 
         int trueWidth = seekBar.getWidth() 
           - seekBar.getPaddingLeft() - seekBar.getPaddingRight(); 

         // what is the position on a 0-1 scale 
         // add 0.3f to avoid roundoff to the next smaller position 
         float relativePos = (0.3f + pos)/(float) seekBar.getMax(); 
         if (relativePos > 1.0f) 
          relativePos = 1.0f; 

         // determine where to click 
         final float screenX = trueWidth*relativePos + screenPos[0] 
           + seekBar.getPaddingLeft(); 
         final float screenY = seekBar.getHeight()/2f + screenPos[1]; 
         float[] coordinates = {screenX, screenY}; 

         return coordinates; 
        } 
       }, 
       Press.FINGER); 
    } 
} 
Смежные вопросы