热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何编写用于Firebase通知的单元测试?

如何解决《如何编写用于Firebase通知的单元测试?》经验,为你挑选了1个好方法。

我做了以下课程来接收Firebase消息并创建通知。我已经通过将Firebase消息发送到应用程序进行了测试,并且效果很好。但是,我需要编写单元测试来测试此功能。但是我为此编写的2个单元测试都失败了。 onMessageReceived()接收RemoteMessage对象中的数据。然后,它查找键的值,type并根据键的值是0还是1,调用buildNotificationBigText()buildNotificationBigPicture()。因此,我编写了2种测试方法。在测试方法中,我创建了一个RemoteMessage对象并将其传递给onMessageReceived()。但是,这些测试无法正常工作,并且出现以下错误:

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 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 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 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 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 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 data = new HashMap<>() ;
            data.put("type","2");
            Mockito.verify(handleFirebaseMessages).buildNotificationBigPicture(data);
        }

}

Jakub Szczyg.. 5

建议在测试时限制要测试的依赖项。您可以采用不依赖FirebaseMessagingService的方式来重构代码。

例如,您可以将其提取为独立于其他类的方法(最好与不依赖FirebaseMessagingService的其他类(以及HandleFirebaseMessages中的其他方法))分离,而不是将其逻辑放在onMessageReceived()中。它甚至可以进行结构化,使其依赖于纯Java代码,因此不需要任何工具即可运行测试。

这样,您将只测试代码,而不测试其他依赖项,这将使测试变得更加容易。



1> Jakub Szczyg..:

建议在测试时限制要测试的依赖项。您可以采用不依赖FirebaseMessagingService的方式来重构代码。

例如,您可以将其提取为独立于其他类的方法(最好与不依赖FirebaseMessagingService的其他类(以及HandleFirebaseMessages中的其他方法))分离,而不是将其逻辑放在onMessageReceived()中。它甚至可以进行结构化,使其依赖于纯Java代码,因此不需要任何工具即可运行测试。

这样,您将只测试代码,而不测试其他依赖项,这将使测试变得更加容易。


推荐阅读
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
author-avatar
珈岩夏17_963
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有