2010-05-10 5 views
5

Je commence par une activité basée sur ce ShakeActivity et je veux écrire quelques tests unitaires pour cela. J'ai déjà écrit quelques petits tests unitaires pour des activités Android mais je ne sais pas par où commencer ici. Je veux alimenter l'accéléromètre avec des valeurs différentes et tester comment l'activité réagit. Pour l'instant je le garde simple et juste en mettant à jour une variable de compteur int privée et un TextView quand un événement "tremblement" se produit.Comment puis-je tester une activité Android agissant sur un accéléromètre?

Donc, ma question se résume en grande partie à ceci:

Comment puis-je envoyer des données fausses à l'accéléromètre à partir d'un test unitaire?

Répondre

5

Ma solution à cela s'est avérée plus simple que prévu. Je ne suis pas vraiment tester l'accéléromètre autant que je teste la réponse de l'application à un événement soulevé par l'accéléromètre, et j'ai juste besoin de tester en conséquence. Ma classe implémente SensorListener et je voulais tester ce qui se passe sur la fonction SensorChanged. La clé était alors de nourrir certaines valeurs et de vérifier l'état de mon activité. Exemple:

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

Comment puis-je envoyer des données fausses à l'accéléromètre d'un test unitaire?

AFAIK, vous ne pouvez pas. Demandez à votre logique Shaker d'accepter une source de données enfichable. Dans le test unitaire, fournissez un simulacre. En production, fournir une enveloppe autour de l'accéléromètre. Ou, ne vous inquiétez pas de l'unité de test du shaker lui-même, mais plutôt de vous inquiéter des tests unitaires qui utilisent le shaker, et de créer un shaker simulé.

+0

Cela a certainement un sens et ne sonne comme une meilleure idée. Avez-vous des exemples d'utilisation d'une "source de données connectable" comme celle-ci? –

+0

Cette réponse est-elle toujours à jour? Ou est-ce que quelque chose de nouveau est sorti? – TinyTimZamboni

+1

@TinyTimZamboni: Je crois me souvenir que l'équipe Android Tools travaillait sur un moyen d'utiliser un appareil Android comme entrée de capteur pour un émulateur, mais je ne sais pas où cela se trouve.Sinon, je ne suis au courant d'aucun moyen de fournir une entrée de faux capteur. – CommonsWare

1

Eh bien, vous pouvez écrire une interface.

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

L'écriture d'un AndroidAccelerometerReader et FakeAccelerometerReader. Votre code utiliserait IAccelerometerReader mais vous pouvez échanger avec les lecteurs Android ou Faux.

0

Pas besoin de tester l'accéléromètre de l'OS, juste tester votre propre logique qui répond à l'OS - autrement dit votre SensorListener. Malheureusement SensorEvent est privé et je ne pouvais pas appeler SensorListener.onSensorChanged(SensorEvent event) directement, donc dû d'abord sous-classe SensorListener avec ma propre classe, et appeler ma propre méthode directement à partir des essais:

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

Ensuite, je peux appeler onSensorUpdated directement à partir de mon code de test , qui simule le déclenchement de l'accéléromètre.

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

    } 
} 

vous pouvez tester ci-dessus morceau de code en suivant façon

@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}); 
    } 
Questions connexes