Как я могу протестировать активность Android, которая работает на акселерометре? - PullRequest
5 голосов
/ 11 мая 2010

Я начинаю с Activity, основанной на этой ShakeActivity , и я хочу написать для нее несколько модульных тестов. Я уже писал несколько небольших юнит-тестов для действий Android, но я не уверен, с чего начать. Я хочу дать акселерометру несколько разных значений и проверить, как активность реагирует на него. Пока я сохраняю это простым и просто обновляю приватную переменную int counter и TextView, когда происходит событие "встряхивания".

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

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

Ответы [ 5 ]

5 голосов
/ 11 мая 2010

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

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 голосов
/ 11 мая 2010

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

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

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

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

1 голос
/ 11 мая 2010

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

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

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

0 голосов
/ 14 августа 2017
  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});
    }
0 голосов
/ 03 апреля 2017

Нет необходимости проверять акселерометр ОС, просто проверьте свою собственную логику, которая реагирует на ОС - другими словами, ваш 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);
}
...