Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write unit tests for firebase notification?

I have made the following class to receive firebase messages and create notifications. I have tested it by sending firebase messages to the app and it works perfectly. However, I need to write unit tests to test this feature. But the 2 unit tests I have written for it are failing. onMessageReceived() receives data in a RemoteMessage object. It then finds the value of the key type and depending on whether it is 0 or 1, it calls either buildNotificationBigText() or buildNotificationBigPicture() . Hence I have written 2 test methods. In my test methods I have created a RemoteMessage object and passed this to onMessageReceived(). However, these tests are not working correctly and I get the following error:

java.lang.NullPointerException: Attempt to invoke virtual method 'void in.ac.bits_pilani.goa.ard.services.HandleFirebaseMessages.onMessageReceived(com.google.firebase.messaging.RemoteMessage)' on a null object reference
at in.ac.bits_pilani.goa.ard.activities.MainActivityTest.handleFirebaseMessageBigPicture(MainActivityTest.java:90)

java.lang.NullPointerException: Attempt to invoke virtual method 'void in.ac.bits_pilani.goa.ard.services.HandleFirebaseMessages.onMessageReceived(com.google.firebase.messaging.RemoteMessage)' on a null object reference
    at in.ac.bits_pilani.goa.ard.activities.MainActivityTest.handleFirebaseMessagesBigText(MainActivityTest.java:80)

HandleFirebaseMessages.java

public class HandleFirebaseMessages extends FirebaseMessagingService {

    /**
     * default id for notification in case specific id is not given in data.
     */
    final int default_id = 42;

    NotificationCompat.Builder builder ;

    /**
     * contains bigTitle value of data in onMessageReceived().
     */
    String bigTitle;

    /**
     * is assigned the bigSummaryText value of data in onMessageReceived().
     */
    String bigSummaryText;

    public HandleFirebaseMessages() {
    }

    /**
     * returns the bitmap image from the url given.
     * @param src image url
     * @return bitmap image at url
     */
    public static Bitmap getBitmapFromURL(final String src) {
        try {
            final URL url = new URL(src);
            final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.connect();
            final InputStream input = connection.getInputStream();
            return BitmapFactory.decodeStream(input);
        } catch (final IOException e) {
            // Log exception
            Log.e("TAG", "fucked man " + e.getMessage());
            return null;
        }
    }

    /**
     * creates the notification when type is 1 or big text.
     * @param data data to be put in notification
     */
    public void buildNotificationBigText(final Map<String, String> data) {
        Log.e("Tag4", "entered buildNotificationBigText");
        //final String bigTitle = data.get("bigTitle");
        final String bigSubTitle = data.get("bigSubTitle");
        //final String bigSummaryText = data.get("bigSummaryText");

        final NotificationCompat.BigTextStyle notificationBigText = new NotificationCompat.BigTextStyle();

        if (bigTitle != null) {
            notificationBigText.setBigContentTitle(bigTitle);
        }
        if (bigSubTitle != null) {
            notificationBigText.bigText(bigSubTitle);
        }
        if (bigSummaryText != null) {
            notificationBigText.setSummaryText(bigSummaryText);
        }

        builder.setStyle(notificationBigText);
    }

    /**
     * creates the notification when type is 2 or big picture.
     * @param data data to be put in notification
     */
    public void buildNotificationBigPicture(final Map<String, String> data) {
        Log.e("Tag3", "entered buildNotificationBigPicture");
        final String imageUrl = data.get("imageUrl");
        //final String bigSummaryText = data.get("bigSummaryText");
        //final String bigTitle = data.get("bigTitle");

        final NotificationCompat.BigPictureStyle notificationBigPicture = new NotificationCompat.BigPictureStyle();
        if (imageUrl != null) {
            final Bitmap image = getBitmapFromURL(imageUrl);
            if (image != null) {
                notificationBigPicture.bigPicture(image);
            } else {
                //TODO Image is null bt url wasn;t!
            }
        }

        if (bigSummaryText != null) {
            notificationBigPicture.setSummaryText(bigSummaryText);
        }
        if (bigTitle != null) {
            notificationBigPicture.setBigContentTitle(bigTitle);
        }
        //TODO icon
        builder.setStyle(notificationBigPicture);
    }

    @Override
    public void onMessageReceived(final RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);

        Log.e("Tag1", "onMessageReceived() started");
        final Map<String, String> data = remoteMessage.getData();

        if (data == null) {
            return;
        }

        bigTitle = data.get("bigTitle");
        bigSummaryText = data.get("bigSummaryText");
        final String type = data.get("type");
        final String id = data.get("id");
        final String smallTitle = data.get("smallTitle");
        final String smallSubTitle = data.get("smallSubTitle");
        //final String contentInfo = data.get("contentInfo");
        //final String ticker = data.get("ticker");
        final String link = data.get("link");
        final String className = data.get("className");

        Log.e("Tag2", "type = " + type);

        builder = new NotificationCompat.Builder(this);

        if (type != null) {
            if (type.compareTo("1") == 0) {
                //Large Text Style corresponds to "1"
                buildNotificationBigText(data);
            } else if (type.compareTo("2") == 0) {
                //BigPicture style specific
                buildNotificationBigPicture(data);
            }
        }

        //General things to be added for any kind of notification
        if (smallTitle != null) {
            builder.setContentTitle(smallTitle);
        }
        if (smallSubTitle != null) {
            builder.setContentText(smallSubTitle);
        }

        int notificationId = default_id;
        if (id != null) {
            notificationId = Integer.parseInt(id);
        }
        builder.setContentIntent(addWebsiteLinkPendingIntent(notificationId, link, className));

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            builder.setCategory(Notification.CATEGORY_SOCIAL);
        }

        builder.setSmallIcon(R.drawable.ic_stat);
        builder.setColor(ContextCompat.getColor(this, R.color.colorPrimary));
        builder.setAutoCancel(true);

        final NotificationManagerCompat mNotificationManager = NotificationManagerCompat.from(this);
        mNotificationManager.notify(notificationId, builder.build());

    }

    /**
     * returns the intent for the webpage or activity to open from the notification.
     * @param id notification id
     * @param link webpage link
     * @param className class for the activity to open
     * @return PendingIntent for the webpage ot activity
     */
    private PendingIntent addWebsiteLinkPendingIntent(final int id, final String link, final String className) {
        Intent intent;

        if (link != null) {
            //TODO Change to ChromeCustomTabs later
            intent = new Intent(Intent.ACTION_VIEW, Uri.parse(link));
        } else if (className != null) {
            try {
                intent = new Intent(this, Class.forName("com.csatimes.dojma." + className));
                //TODO check for page number
            } catch (final ClassNotFoundException e) {
                intent = new Intent(this, MainActivity.class);
            }
            intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
        } else {
            intent = new Intent(this, MainActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION);
        }

        return PendingIntent.getActivity(
                this,
                id,
                intent,
                PendingIntent.FLAG_CANCEL_CURRENT);
    }

}

MainActivityTests.java :

  @RunWith(AndroidJUnit4.class)
public class MainActivityTest {

    private Context context;

    @Mock
    private HandleFirebaseMessages handleFirebaseMessages;

    @Rule
    public ActivityTestRule<MainActivity> activityTestRule =
            new ActivityTestRule<>(MainActivity.class);

    @Before
    public void init() {
        context = InstrumentationRegistry.getTargetContext();
        //MockitoAnnotations.initMocks(this);
        //handleFirebaseMessages = new HandleFirebaseMessages();
    }

     @Test
        public void handleFirebaseMessagesBigText() {
            HandleFirebaseMessages handleFirebaseMessages=new HandleFirebaseMessages();
            RemoteMessage remoteMessage = new RemoteMessage.Builder("token").addData("type","1").build();
            handleFirebaseMessages.onMessageReceived(remoteMessage);
            Map<String,String> data = new HashMap<>() ;
            data.put("type","1");
            Mockito.verify(handleFirebaseMessages).buildNotificationBigText(data);
        }

        @Test
        public void handleFirebaseMessagesBigPicture() {
            HandleFirebaseMessages handleFirebaseMessages=new HandleFirebaseMessages();
            RemoteMessage remoteMessage = new RemoteMessage.Builder("token").addData("type","2").build();
            handleFirebaseMessages.onMessageReceived(remoteMessage);
            Map<String,String> data = new HashMap<>() ;
            data.put("type","2");
            Mockito.verify(handleFirebaseMessages).buildNotificationBigPicture(data);
        }

}
like image 923
Nirvan Anjirbag Avatar asked Mar 09 '23 22:03

Nirvan Anjirbag


1 Answers

While testing it is advised to limit dependencies that you are testing. You could refactor your code in a way that it would not depend on FirebaseMessagingService.

For example instead of having your logic in onMessageReceived(), you could extract it to separate method preferably in other class (along with other methods from HandleFirebaseMessages) that would not depend on FirebaseMessagingService. It could even be structured so that it relies on plain java code, so that no instrumentation is required to run the test.

This way you would only be testing your code and not other dependencies, which would make it easier to test.

like image 59
Jakub Szczygieł Avatar answered Mar 28 '23 09:03

Jakub Szczygieł