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);
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With