google/mobly-bundled-snippets

android Instrument test for Snippet?

Opened this issue · 10 comments

Hello, i tried to write a test class for a specific snippet, but i cannot make it work.
Any suggestion?


import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class DemoTest {

    @Test
    public void testAudioSnippet() {
        AudioSnippet audioSnippet = new AudioSnippet();
        audioSnippet.getMusicMaxVolume();
    }
}

And here is the output when i run test case

Testing started at 12:46 PM ...

04/06 12:46:19: Launching 'testAudioSnippet()' on samsung SM-A530F.
Running tests

$ adb shell am instrument -w -r   -e debug false -e class 'com.google.android.mobly.snippet.bundled.DemoTest#testAudioSnippet' com.google.android.mobly.snippet.bundled.test/com.google.android.mobly.snippet.SnippetRunner
Waiting for process to come online...
Connected to process 14915 on device 'samsung-sm_a530f-5200b9494d8c749d'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I/snippet.bundle: The ClassLoaderContext is a special shared library.
I/snippet.bundle: The ClassLoaderContext is a special shared library.
I/snippet.bundle: The ClassLoaderContext is a special shared library.
I/snippet.bundle: The ClassLoaderContext is a special shared library.
I/snippet.bundle: The ClassLoaderContext is a special shared library.
I/snippet.bundle: The ClassLoaderContext is a special shared library.
W/snippet.bundle: Accessing hidden method Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Landroid/app/Activity;Landroid/content/Intent;ILandroid/os/Bundle;)Landroid/app/Instrumentation$ActivityResult; (light greylist, linking)
    Accessing hidden method Landroid/app/Instrumentation;->execStartActivity(Landroid/content/Context;Landroid/os/IBinder;Landroid/os/IBinder;Ljava/lang/String;Landroid/content/Intent;ILandroid/os/Bundle;)Landroid/app/Instrumentation$ActivityResult; (light greylist, linking)
I/MultiDex: VM with version 2.1.0 has multidex support
    Installing application
    VM has multidex support, MultiDex support library is disabled.
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.google.android.mobly.snippet.bundled, PID: 14915
    java.lang.RuntimeException: Exception thrown in onCreate() of ComponentInfo{com.google.android.mobly.snippet.bundled.test/com.google.android.mobly.snippet.SnippetRunner}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6242)
        at android.app.ActivityThread.access$1200(ActivityThread.java:237)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1792)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7073)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference
        at com.google.android.mobly.snippet.util.Log.initLogTag(Log.java:44)
        at com.google.android.mobly.snippet.SnippetRunner.onCreate(SnippetRunner.java:98)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6237)
        at android.app.ActivityThread.access$1200(ActivityThread.java:237) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1792) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7073) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964) 
I/Process: Sending signal. PID: 14915 SIG: 9

Started running tests
Test running failed: Instrumentation run failed due to 'Process crashed.'

Did you add this class's path to the manifest?

I've changed anything with original AndroidManifest.xml
What do i should add to?

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.google.android.mobly.snippet.bundled">

    <uses-feature android:name="android.hardware.telephony" android:required="false" />

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    <application android:allowBackup="false"
                 android:name="androidx.multidex.MultiDexApplication">
        <meta-data
            android:name="mobly-snippets"
            android:value="com.google.android.mobly.snippet.bundled.AccountSnippet,
                           com.google.android.mobly.snippet.bundled.AudioSnippet,
                           com.google.android.mobly.snippet.bundled.bluetooth.BluetoothAdapterSnippet,
                           com.google.android.mobly.snippet.bundled.bluetooth.profiles.BluetoothA2dpSnippet,
                           com.google.android.mobly.snippet.bundled.bluetooth.profiles.BluetoothHearingAidSnippet,
                           com.google.android.mobly.snippet.bundled.BluetoothLeAdvertiserSnippet,
                           com.google.android.mobly.snippet.bundled.BluetoothLeScannerSnippet,
                           com.google.android.mobly.snippet.bundled.LogSnippet,
                           com.google.android.mobly.snippet.bundled.MediaSnippet,
                           com.google.android.mobly.snippet.bundled.NotificationSnippet,
                           com.google.android.mobly.snippet.bundled.TelephonySnippet,
                           com.google.android.mobly.snippet.bundled.NetworkingSnippet,
                           com.google.android.mobly.snippet.bundled.FileSnippet,
                           com.google.android.mobly.snippet.bundled.SmsSnippet,
                           com.google.android.mobly.snippet.bundled.WifiManagerSnippet,
                           com.google.android.mobly.snippet.bundled.StorageSnippet" />
    </application>

    <instrumentation
        android:name="com.google.android.mobly.snippet.SnippetRunner"
        android:targetPackage="com.google.android.mobly.snippet.bundled" />
</manifest>

Oh wait, are you trying to add unit tests for a snippet java class?

Oh wait, are you trying to add unit tests for a snippet java class?

Yep, actually i want to speed up test process for snippet by creating a test class,
For now, i'm using snippet_shell.py to test my function

I see.
I don't think there's anything special about MBS code.
You can just use Android instrumentation test to test against it as a regular Android lib.

But I don't think it's very useful bc MBS mostly calls platform APIs, which triggers actual device behaviors.
Unit tests won't be able to validate these fully.

+1 to this, it would be good to have instrumentation tests for the existing snippets. Useful at minimum when changing something like AGP versions or targetSDK, to test stuff still works.

Unfortunately we don't have enough resource for this.

MBS has a lot of connectivity APIs
We'd essentially need to write roboelectric tests for them.
And roboelectric doesn't have good support for Android connectivity APIs to begin with..

I think this issue is thoroughly discussed here.
Can file new issues when actions are ready to be taken.

Yep, I'll raise a separate issue.

I wasn't suggesting unit tests with Robolectric, but that would be good also. More some instrumentation tests that confirm things like the code passes on the target SDK, or some new platform (wear, or TV).

How you would confirm the API actually behaved though?
It sounds like end to end or integration tests? Who would provide the HW to run those on?