11

Voglio testare da un'unità di test se una notifica è in grado di riprodurre un suono personalizzato dalle risorse. Il test non ha lo scopo di verificare nulla, l'ho scritto come un modo rapido per dimostrare una funzionalità senza ingombrare il codice dell'app principale.Creazione di notifiche da InstrumentationTestCase

Quindi nel progetto di test, ho aggiunto un file wav all'interno di /res/raw. Userò questo URL con il costruttore di notifica:

Uri path = Uri.parse("android.resource://<main app package name>/testsound.wav"); 

Questo URL dovrebbe funzionare in base alle domande che ho letto in SO. Supponiamo che funzioni.

Ora perché non ho voglia di includere il file di test wav nella cartella del progetto principale /res/raw ma nel progetto di test, io sono costretto a fare il mio test di unità si estendono dalla InstrumentationTestCase modo che io possa accedere alle risorse in il progetto di test.

Ecco il codice:

NotificationCompat.Builder builder = new NotificationCompat.Builder(getInstrumentation().getContext()); 
    ... 
    builder.setSound(path, AudioManager.STREAM_NOTIFICATION); 
    ... 
    NotificationManager notificationManager = (NotificationManager) getInstrumentation().getContext().getSystemService(Context.NOTIFICATION_SERVICE); 
    notificationManager.notify(NOTIFICATION_ID, builder.build()); 

La chiamata notify sta gettando la seguente eccezione:

java.lang.SecurityException: Calling uid 10198 gave package <main app package name> which is owned by uid 10199 
    at android.os.Parcel.readException(Parcel.java:1540) 
    at android.os.Parcel.readException(Parcel.java:1493) 
    at android.app.INotificationManager$Stub$Proxy.enqueueNotificationWithTag(INotificationManager.java:611) 
    at android.app.NotificationManager.notify(NotificationManager.java:187) 
    at android.app.NotificationManager.notify(NotificationManager.java:140) 
    ... 
    at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1873) 

ho rintracciato questa eccezione fino alla classe di NotificationManagerService:

void checkCallerIsSystemOrSameApp(String pkg) { 
     int uid = Binder.getCallingUid(); 
     if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) { 
      return; 
     } 
     try { 
      ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
        pkg, 0, UserHandle.getCallingUserId()); 
      if (!UserHandle.isSameApp(ai.uid, uid)) { 
       throw new SecurityException("Calling uid " + uid + " gave package" 
         + pkg + " which is owned by uid " + ai.uid); 
      } 
     } catch (RemoteException re) { 
      throw new SecurityException("Unknown package " + pkg + "\n" + re); 
     } 
    } 

Apparentemente l'eccezione non ha nulla a che fare con l'abitudine suono, ma con il fatto che stiamo creando una notifica da un InstrumentationTestCase.

C'è un modo per testarlo? Ricordo di aver creato notifiche da AndroidTestCase in passato, ma se lo faccio, non sarò in grado di accedere al file di test wav. Potrei creare un jar con il wav e rilasciare il jar nella cartella lib del progetto di test, ma questo potrebbe nascondere il file, e altri programmatori potrebbero avere difficoltà a cercarlo se hanno bisogno di sostituirlo in futuro.

risposta

0

Ho immaginato come far funzionare il suono da un AndroidTestCase. Il file wav è stato aggiunto alla cartella raw del progetto di test e non è stato incluso nel progetto principale come previsto.

L'URL per la notifica è stata in questo modo:

Uri path = Uri.parse("android.resource://<test project package name>/" + R.raw.air_horn); 

e il costruttore è stato ottenuto come segue:

NotificationCompat.Builder builder = new NotificationCompat.Builder(getContext()); 
2

In realtà, sono rimasto un po 'perplesso dalla domanda. Così ho scritto un piccolo test di strumentazione.

Per motivi di affermazione, ho contrassegnato il test per l'esecuzione solo su API 23 (getActiveNotifications sembra non essere disponibile prima), ma funziona bene anche sulle API precedenti.

Il trucco è quello di utilizzare getTargetContext() invece di getContext():

public final class MainActivityTest extends ActivityUnitTestCase<MainActivity> { 

    public MainActivityTest() { 
     super(MainActivity.class); 
    } 

    @TargetApi(Build.VERSION_CODES.M) 
    public void testSendNotification() { 
     final NotificationManager manager = (NotificationManager) getInstrumentation().getTargetContext().getSystemService(Context.NOTIFICATION_SERVICE); 

     manager.cancel(42); 
     assertEquals(0, manager.getActiveNotifications().length); 

     final NotificationCompat.Builder builder = new NotificationCompat.Builder(getInstrumentation().getTargetContext()); 
     builder.setContentTitle("Notification test") 
       .setAutoCancel(true) 
       .setContentText("Hello, Mister Smith") 
       .setSmallIcon(R.drawable.ic_launcher_notification); 

     manager.notify(42, builder.build()); 

     assertEquals(1, manager.getActiveNotifications().length); 
    } 
} 

Funziona come un fascino:

enter image description here

Speranza, aiuta.

+0

Sì, questo funziona. Il file wav viene riprodotto come previsto. L'unico inconveniente è che hai bisogno di un'attività dal tuo progetto principale. –

+0

@MisterSmith ma hai chiesto informazioni su ** Instrumentation test **, non su unit test. La tua risposta non riflette la domanda che chiedi. –

+0

Sì, mi dispiace per quello. Supponevo che per accedere a una risorsa nel progetto di test dovessi usare la strumentazione, come descritto in [questa domanda] (http://stackoverflow.com/questions/9249751/accessing-resources-in-an-android- test-project)). Ma si è scoperto che funziona con un normale test unitario. Grazie comunque. –