How can I unit test an Android Activity that acts on Accelerometer?

后端 未结 5 1072
心在旅途
心在旅途 2021-01-03 04:00

I am starting with an Activity based off of this ShakeActivity and I want to write some unit tests for it. I have written some small unit tests for Android activities befor

相关标签:
5条回答
  • 2021-01-03 04:18

    How can I send fake data to the accelerometer from a unit test?

    AFAIK, you can't.

    Have your shaker logic accept a pluggable data source. In the unit test, supply a mock. In production, supply a wrapper around the accelerometer.

    Or, don't worry about unit testing the shaker itself, but rather worry about unit testing things that use the shaker, and create a mock shaker.

    0 讨论(0)
  • 2021-01-03 04:29

    Well, you can write an interface.

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

    The write an AndroidAccelerometerReader and FakeAccelerometerReader. Your code would use IAccelerometerReader but you can swap in the Android or Fake readers.

    0 讨论(0)
  • 2021-01-03 04:32
      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];
            }
    
         }
    } 
    

    you can test above piece of code by following way

    @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 讨论(0)
  • 2021-01-03 04:38

    No need to test the OS's accelerometer, just test your own logic that responds to the OS - in other words your SensorListener. Unfortunately SensorEvent is private and I could not call SensorListener.onSensorChanged(SensorEvent event) directly, so had to first subclass SensorListener with my own class, and call my own method directly from the tests:

    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
         }
    }
    

    Then I can call onSensorUpdated directly from my test code, which simulates the accelerometer firing.

    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 讨论(0)
  • 2021-01-03 04:40

    My solution to this ended up way simpler then I expected. I'm not really testing the accelerometer so much as I am testing the application's response to an event raised by the accelerometer, and I just needed to test accordingly. My class implements SensorListener and I wanted to test what happens onSensorChanged. The key then was to feed in some values and check my Activity's state. Example:

    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);
    }
    
    0 讨论(0)
提交回复
热议问题