5

我从一个基于这个ShakeActivity的 Activity 开始,我想为它编写一些单元测试。我之前为 Android 活动编写了一些小型单元测试,但我不确定从哪里开始。我想为加速度计提供一些不同的值并测试活动如何响应它。现在我保持简单,只是在“摇动”事件发生时更新一个私有 int 计数器变量和一个 TextView。

所以我的问题很大程度上归结为:

如何从单元测试向加速度计发送假数据?

4

5 回答 5

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);
}
于 2010-05-11T19:18:52.527 回答
4

如何从单元测试向加速度计发送假数据?

AFAIK,你不能。

让您的振动器逻辑接受可插入的数据源。在单元测试中,提供一个模拟。在生产中,在加速度计周围提供一个包装器。

或者,不要担心对振动器本身进行单元测试,而是担心对使用振动器的东西进行单元测试,并创建一个模拟振动器。

于 2010-05-11T00:00:00.360 回答
1

好吧,你可以写一个接口。

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

写一个AndroidAccelerometerReaderFakeAccelerometerReader。您的代码可以使用IAccelerometerReader,但您可以换用 Android 或 Fake 阅读器。

于 2010-05-11T19:08:53.003 回答
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);
}
于 2017-04-03T20:34:02.807 回答
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});
    }
于 2017-08-13T21:32:40.643 回答