2010-05-10 2 views
5

Я начинаю с деятельности, основанной на этом ShakeActivity, и я хочу написать для него некоторые модульные тесты. Ранее я написал несколько небольших тестов для Android, но не знаю, с чего начать. Я хочу передать акселерометру несколько разных значений и проверить, как реагирует на него активность. На данный момент я сохраняю это просто и просто обновляю переменную счетчика private int и TextView, когда происходит событие «встряхивания».Как я могу протестировать Android-активность, действующую на Accelerometer?

Так что мой вопрос в основном сводится к следующему:

Как я могу отправить поддельные данные на акселерометр от модульного тестирования?

ответ

5

Мое решение для этого оказалось проще, чем я ожидал. Я не тестирую акселерометр, так как тестирую реакцию приложения на событие, возбужденное акселерометром, и мне просто нужно было проверить его. Мой класс реализует SensorListener, и я хотел проверить, что происходит onSensorChanged. Ключ тогда должен был подпитывать некоторые значения и проверять состояние моей активности. Пример:

public void testShake() throws InterruptedException { 
    mShaker.onSensorChanged(SensorManager.SENSOR_ACCELEROMETER, new float[] {0, 0, 0}); 
    //Required because method only allows one shake per 100ms 
    Thread.sleep(500); 
    mShaker.onSensorChanged(SensorManager.SENSOR_ACCELEROMETER, new float[] {300, 300, 300}); 
    Assert.assertTrue("Counter: " + mShaker.shakeCounter, mShaker.shakeCounter > 0); 
} 
4

Как я могу отправить поддельные данные в акселерометра от модульного тестирования?

AFAIK, вы не можете.

Имейте свою логику шейкера принять подключаемый источник данных. В модульном тесте поставьте макет. В производстве поставьте обертку вокруг акселерометра.

Или не беспокойтесь о модуле тестирования самого шейкера, а скорее беспокоитесь об аппаратном тестировании вещей, которые используют шейкер, и создайте макет шейкера.

+0

Это, конечно, имеет смысл и звучит как лучшая идея. Есть ли у вас примеры использования «подключаемого источника данных»? –

+0

Является ли этот ответ еще актуальным? Или что-то новое вышло? – TinyTimZamboni

+1

@TinyTimZamboni: Мне кажется, что команда Android Tools работала над тем, как использовать Android-устройство в качестве входного сигнала датчика для эмулятора, но я не знаю, где это стоит.В противном случае, я не знаю, какой способ обеспечить ввод ложных датчиков. – CommonsWare

1

Ну, вы можете написать интерфейс.

interface IAccelerometerReader { 
    public float[] readAccelerometer(); 
} 

The написать AndroidAccelerometerReader и FakeAccelerometerReader. Ваш код будет использовать IAccelerometerReader, но вы можете поменять местами на устройствах Android или Fake.

0

Нет необходимости проверять акселерометр ОС, просто проверить свою собственную логику, которая реагирует на ОС - другими словами, ваш SensorListener. К сожалению SensorEvent является частным, и я не мог назвать SensorListener.onSensorChanged(SensorEvent event) напрямую, поэтому должен был первым подкласс SensorListener с моим собственным классом, и назвать свой собственный метод непосредственно из тестов:

public class ShakeDetector implements SensorEventListener { 

    @Override 
    public void onSensorChanged(SensorEvent event) { 

     float x = event.values[0]; 
     float y = event.values[1]; 
     float z = event.values[2]; 

     onSensorUpdate(x, y, z); 
    } 

    public void onSensorUpdate(float x, float y, float z) { 
     // do my (testable) logic here 
    } 
} 

Тогда я могу позвонить onSensorUpdated непосредственно из моего тестового кода , который имитирует стрельбу акселерометром.

private void simulateShake(final float amplitude, int interval, int duration) throws InterruptedException { 
    final SignInFragment.ShakeDetector shaker = getFragment().getShakeSensorForTesting(); 
    long start = System.currentTimeMillis(); 

    do { 
     getInstrumentation().runOnMainSync(new Runnable() { 
      @Override 
      public void run() { 
       shaker.onSensorUpdate(amplitude, amplitude, amplitude); 
      } 
     }); 
     Thread.sleep(interval); 
    } while (System.currentTimeMillis() - start < duration); 
} 
0
public class SensorService implements SensorEventListener { 
/** 
    * Accelerometer values 
    */ 
    private float accValues[] = new float[3]; 
    @Override 
    public void onSensorChanged(SensorEvent event) { 

      if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { 
      accValues[0] = sensorEvent.values[0]; 
      accValues[1] = sensorEvent.values[1]; 
      accValues[2] = sensorEvent.values[2]; 
     } 

    } 
} 

вы можете проверить выше кусок кода, следуя путем

@Test 
    public void testOnSensorChangedForAcceleratorMeter() throws Exception { 
     Intent intent=new Intent(); 
     sensorService.onStartCommand(intent,-1,-1); 

     SensorEvent sensorEvent=getEvent(); 
     Sensor sensor=getSensor(Sensor.TYPE_ACCELEROMETER); 
     sensorEvent.sensor=sensor; 
     sensorEvent.values[0]=1.2345f; 
     sensorEvent.values[1]=2.45f; 
     sensorEvent.values[2]=1.6998f; 
     sensorService.onSensorChanged(sensorEvent); 

     Field field=sensorService.getClass().getDeclaredField("accValues"); 
     field.setAccessible(true); 
     float[] result= (float[]) field.get(sensorService); 
     Assert.assertEquals(sensorEvent.values.length,result.length); 
     Assert.assertEquals(sensorEvent.values[0],result[0],0.0f); 
     Assert.assertEquals(sensorEvent.values[1],result[1],0.0f); 
     Assert.assertEquals(sensorEvent.values[2],result[2],0.0f); 
    } 




private Sensor getSensor(int type) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException { 
      Constructor<Sensor> constructor = Sensor.class.getDeclaredConstructor(new Class[0]); 
      constructor.setAccessible(true); 
      Sensor sensor= constructor.newInstance(new Object[0]); 

      Field field=sensor.getClass().getDeclaredField("mType"); 
      field.setAccessible(true); 
      field.set(sensor,type); 
      return sensor; 
     } 



private SensorEvent getEvent() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { 
     Constructor<SensorEvent> constructor = SensorEvent.class.getDeclaredConstructor(int.class); 
     constructor.setAccessible(true); 
     return constructor.newInstance(new Object[]{3}); 
    } 
Смежные вопросы