代码之家  ›  专栏  ›  技术社区  ›  Corey Sunwold

如何对作用于加速度计的Android活动进行单元测试?

  •  5
  • Corey Sunwold  · 技术社区  · 14 年前

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

    所以我的问题主要归结为:

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

    5 回复  |  直到 14 年前
        1
  •  5
  •   Carl Manaster    14 年前

    我的解决方案比我想象的要简单得多。我并不是真正测试加速度计,而是测试应用程序对加速度计引发的事件的响应,我只是需要相应地测试。我的类实现 SensorListener 我想测试一下当我们被绞死时会发生什么。关键是输入一些值并检查我的活动状态。例子:

    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);
    }
    
        2
  •  4
  •   CommonsWare    14 年前

    我如何将假数据发送到 来自单元测试的加速度计?

    阿法克,你不能。

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

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

        3
  •  1
  •   Nikhil Freddroid    12 年前

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

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

    写一篇文章 AndroidAccelerometerReader FakeAccelerometerReader . 您的代码将使用 IAccelerometerReader 但是你可以在Android中交换或者伪造阅读器。

        4
  •  0
  •   Marc Attinasi    7 年前

    无需测试操作系统的加速度计,只需测试您自己响应操作系统的逻辑——换句话说,您的 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);
    }
    
        5
  •  0
  •   Sanjoy Saha    7 年前
      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});
        }