【问题标题】:Flutter Test: temporarily disable Firebase or somehow make the test not fail because of Firebase?Flutter 测试:暂时禁用 Firebase 或以某种方式使测试不会因为 Firebase 而失败?
【发布时间】:2022-01-19 09:57:27
【问题描述】:

我写了一个测试:

homeScreenWidgetsTest() {
  testWidgets('Home page screen widgets', (WidgetTester tester) async {
   
    await tester.pumpWidget(
      MaterialApp(
          home:Provider<AppDatabase>(
              create: (context) => AppDatabase(),
              child: HomePage(),
              dispose: (context, db) => db.close(),
            ),
      ),
    );

    await tester.pumpAndSettle(Duration(seconds: 15));
    expect(find.byType(AppBar), findsOneWidget);
  });
}

它会抛出这个错误:

══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following FirebaseException was thrown running a test:
[core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()

When the exception was thrown, this was the stack:
#0      MethodChannelFirebase.app (package:firebase_core_platform_interface/src/method_channel/method_channel_firebase.dart:149:5)
#1      Firebase.app (package:firebase_core/src/firebase.dart:55:41)
#2      FirebaseCrashlytics.instance (package:firebase_crashlytics/src/firebase_crashlytics.dart:33:55)
#3      FirebaseLogging.log (package:.../logging/firebase_logging.dart:5:25)
#4      MyClass.work (package:.../oauth/oauth.dart:136:21)
<asynchronous suspension>

错误发生在日志行:

static Future<bool> work() async {
    FirebaseLogging.log("Start work.");

如果我在测试的主要方法中添加Firebase.initializeApp()

Future<void> main() async {
  await Firebase.initializeApp();
  homeScreenWidgetsTest();
}

它会抛出这些错误:

package:flutter/src/services/platform_channel.dart 142:86                                       MethodChannel.binaryMessenger
package:flutter/src/services/platform_channel.dart 148:36                                       MethodChannel._invokeMethod
package:flutter/src/services/platform_channel.dart 331:12                                       MethodChannel.invokeMethod
package:flutter/src/services/platform_channel.dart 344:41                                       MethodChannel.invokeListMethod
package:firebase_core_platform_interface/src/method_channel/method_channel_firebase.dart 31:37  MethodChannelFirebase._initializeCore
package:firebase_core_platform_interface/src/method_channel/method_channel_firebase.dart 73:13  MethodChannelFirebase.initializeApp
package:firebase_core/src/firebase.dart 42:47                                                   Firebase.initializeApp
test\home_screen_test.dart 14:18                                                         main

Failed to load "E:\...\home_screen_test.dart": Null check operator used on a null value

所以它在这一行抛出错误:await Firebase.initializeApp();

如何解决这个问题?提前致谢。

这是 FirebaseLogging.log():

class FirebaseLogging {
  static void log(String log) {
    FirebaseCrashlytics.instance.log(log);
  }
}

【问题讨论】:

    标签: firebase flutter testing


    【解决方案1】:

    我在更新 Firebase 软件包时遇到了同样的问题。

    我创建了一个类来根据环境将FirebaseAnalytics 与模拟版本交换。然后将FirebaseAnalytics替换为包装类AnalyticsService

    这太老套了,我讨厌它。

    如果有人有更好的方法,请分享。

    import 'dart:io';
    
    import 'package:firebase_analytics/firebase_analytics.dart';
    import 'package:firebase_core/firebase_core.dart';
    
    // The is class is needed because firebase is horrible and apparently hates developers
    // - also calling `FirebaseAnalytics.instance` causes tests to fail
    class AnalyticsService {
      static get instance => Platform.environment.containsKey('FLUTTER_TEST') ? FakeFirebaseAnalytics() : FirebaseAnalytics.instance;
    }
    
    class FakeFirebaseAnalytics implements FirebaseAnalytics {
      @override
      FirebaseApp app;
    
      @override
      FirebaseAnalyticsAndroid get android => null;
    
      @override
      Future<void> logAdImpression({String adPlatform, String adSource, String adFormat, String adUnitName, double value, String currency, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logAddPaymentInfo({String coupon, String currency, String paymentType, double value, List<AnalyticsEventItem> items, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logAddShippingInfo({String coupon, String currency, double value, String shippingTier, List<AnalyticsEventItem> items, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logAddToCart({List<AnalyticsEventItem> items, double value, String currency, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logAddToWishlist({List<AnalyticsEventItem> items, double value, String currency, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logAppOpen({AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logBeginCheckout({double value, String currency, List<AnalyticsEventItem> items, String coupon, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logCampaignDetails({String source, String medium, String campaign, String term, String content, String aclid, String cp1, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logEarnVirtualCurrency({String virtualCurrencyName, num value, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logEcommercePurchase(
          {String currency,
          double value,
          String transactionId,
          double tax,
          double shipping,
          String coupon,
          String location,
          int numberOfNights,
          int numberOfRooms,
          int numberOfPassengers,
          String origin,
          String destination,
          String startDate,
          String endDate,
          String travelClass}) async {}
    
      @override
      Future<void> logEvent({String name, Map<String, Object> parameters, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logGenerateLead({String currency, double value, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logJoinGroup({String groupId, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logLevelEnd({String levelName, int success, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logLevelStart({String levelName, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logLevelUp({int level, String character, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logLogin({String loginMethod, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logPostScore({int score, int level, String character, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logPresentOffer({String itemId, String itemName, String itemCategory, int quantity, double price, double value, String currency, String itemLocationId}) async {}
    
      @override
      Future<void> logPurchase(
          {String currency, String coupon, double value, List<AnalyticsEventItem> items, double tax, double shipping, String transactionId, String affiliation, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logPurchaseRefund({String currency, double value, String transactionId}) async {}
    
      @override
      Future<void> logRefund({String currency, String coupon, double value, double tax, double shipping, String transactionId, String affiliation, List<AnalyticsEventItem> items}) async {}
    
      @override
      Future<void> logRemoveFromCart({String currency, double value, List<AnalyticsEventItem> items, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logScreenView({String screenClass, String screenName, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logSearch(
          {String searchTerm,
          int numberOfNights,
          int numberOfRooms,
          int numberOfPassengers,
          String origin,
          String destination,
          String startDate,
          String endDate,
          String travelClass,
          AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logSelectContent({String contentType, String itemId}) async {}
    
      @override
      Future<void> logSelectItem({String itemListId, String itemListName, List<AnalyticsEventItem> items, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logSelectPromotion(
          {String creativeName, String creativeSlot, List<AnalyticsEventItem> items, String locationId, String promotionId, String promotionName, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logSetCheckoutOption({int checkoutStep, String checkoutOption}) async {}
    
      @override
      Future<void> logShare({String contentType, String itemId, String method}) async {}
    
      @override
      Future<void> logSignUp({String signUpMethod}) async {}
    
      @override
      Future<void> logSpendVirtualCurrency({String itemName, String virtualCurrencyName, num value}) async {}
    
      @override
      Future<void> logTutorialBegin() async {}
    
      @override
      Future<void> logTutorialComplete() async {}
    
      @override
      Future<void> logUnlockAchievement({String id}) async {}
    
      @override
      Future<void> logViewCart({String currency, double value, List<AnalyticsEventItem> items, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> logViewItem({String currency, double value, List<AnalyticsEventItem> items}) async {}
    
      @override
      Future<void> logViewItemList({List<AnalyticsEventItem> items, String itemListId, String itemListName}) async {}
    
      @override
      Future<void> logViewPromotion({String creativeName, String creativeSlot, List<AnalyticsEventItem> items, String locationId, String promotionId, String promotionName}) async {}
    
      @override
      Future<void> logViewSearchResults({String searchTerm}) async {}
    
      @override
      Future<void> resetAnalyticsData() async {}
    
      @override
      Future<void> setAnalyticsCollectionEnabled(bool enabled) async {}
    
      @override
      Future<void> setConsent({bool adStorageConsentGranted, bool analyticsStorageConsentGranted}) async {}
    
      @override
      Future<void> setCurrentScreen({String screenName, String screenClassOverride = 'Flutter', AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> setDefaultEventParameters(Map<String, Object> defaultParameters) async {}
    
      @override
      Future<void> setSessionTimeoutDuration(Duration timeout) async {}
    
      @override
      Future<void> setUserId({String id, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Future<void> setUserProperty({String name, String value, AnalyticsCallOptions callOptions}) async {}
    
      @override
      Map get pluginConstants => {};
    }
    

    将此技巧应用于问题中的代码:

    class FirebaseLogging {
      static void log(String log) {
        if (Platform.environment.containsKey('FLUTTER_TEST')) return; 
        FirebaseCrashlytics.instance.log(log);
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-20
      • 2020-02-16
      • 1970-01-01
      相关资源
      最近更新 更多