Skip to content

Commit 1fb1570

Browse files
Rjaintwilioedsonjabnd4p90xrishabh-twilioMichaelGHSeg
authored
Added unit test cases (#125)
* Add first unit test to project * Add new unit test * Add new unit test to increase coverage * Update library test and fix issue reported by 'analyze' * Fixed errors after merging with main. * Fixed flutter analyze warnings * Updated flush_policy_test.dart --------- Co-authored-by: Edson Amaya <edson.amaya.dev@gmail.com> Co-authored-by: Shane L. Duvall <sduvall@mark4tech.com> Co-authored-by: Rishabh Jain <risjain@twilio.com> Co-authored-by: Michael Grosse Huelsewiesche <mihuelsewiesche@twilio.com>
1 parent 3eedee4 commit 1fb1570

35 files changed

+3769
-70
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,7 @@ build/
3838
launch.json
3939

4040
#Coverage
41-
coverage/
41+
coverage/
42+
43+
# FVM Version Cache
44+
.fvm/

packages/core/lib/analytics_pigeon.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
import 'package:segment_analytics/analytics_platform_interface.dart';
23
import 'package:flutter/services.dart';
34

@@ -7,11 +8,13 @@ import 'native_context.dart';
78
class AnalyticsPlatformImpl extends AnalyticsPlatform {
89
static const EventChannel _eChannel =
910
EventChannel('analytics/deep_link_events');
10-
final NativeContextApi _api = NativeContextApi();
11+
NativeContextApi api;
12+
13+
AnalyticsPlatformImpl({NativeContextApi? api}) : api = api ?? NativeContextApi();
1114

1215
@override
1316
Future<NativeContext> getContext({bool collectDeviceId = false}) {
14-
return _api.getContext(collectDeviceId);
17+
return api.getContext(collectDeviceId);
1518
}
1619

1720
@override

packages/core/lib/flush_policies/count_flush_policy.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:flutter/foundation.dart';
12
import 'package:segment_analytics/event.dart';
23
import 'package:segment_analytics/flush_policies/flush_policy.dart';
34

@@ -7,6 +8,9 @@ class CountFlushPolicy extends FlushPolicy {
78

89
CountFlushPolicy(this._flushAt, {int? count}) : _count = count ?? 0;
910

11+
@visibleForTesting
12+
int get count => _count;
13+
1014
@override
1115
void start() {
1216
_count = 0;

packages/core/lib/plugins/segment_destination.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ class SegmentDestination extends DestinationPlugin with Flushable {
1515
String? _apiHost;
1616

1717
SegmentDestination() : super(segmentDestinationKey) {
18-
_queuePlugin = QueueFlushingPlugin(_sendEvents);
18+
_queuePlugin = QueueFlushingPlugin(sendEvents);
1919
}
2020

21-
Future _sendEvents(List<RawEvent> events) async {
21+
Future sendEvents(List<RawEvent> events) async {
2222
if (events.isEmpty) {
2323
return;
2424
}

packages/core/lib/utils/lifecycle/fgbg.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ import 'package:segment_analytics/utils/lifecycle/lifecycle.dart';
44
import 'package:flutter_fgbg/flutter_fgbg.dart';
55

66
class FGBGLifecycle extends LifeCycle {
7-
final _stream = FGBGEvents.instance.stream;
7+
final Stream<FGBGType> stream;
8+
9+
FGBGLifecycle(this.stream);
810

911
@override
1012
StreamSubscription<AppStatus> listen(void Function(AppStatus event)? onData,
1113
{Function? onError, void Function()? onDone, bool? cancelOnError}) {
12-
return _stream
14+
return stream
1315
.map((event) => (event == FGBGType.foreground)
1416
? AppStatus.foreground
1517
: AppStatus.background)
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:async';
22
import 'dart:io';
33

4+
import 'package:flutter_fgbg/flutter_fgbg.dart';
45
import 'package:segment_analytics/utils/lifecycle/fgbg.dart';
56
import 'package:segment_analytics/utils/lifecycle/widget_observer.dart';
67
import 'package:flutter/foundation.dart';
@@ -9,16 +10,17 @@ enum AppStatus { foreground, background }
910

1011
abstract class LifeCycle extends Stream<AppStatus> {}
1112

12-
LifeCycle _getLifecycleStream() {
13+
@visibleForTesting
14+
LifeCycle getLifecycleStream() {
1315
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
1416
// For iOS and Android we will use the FgBg Lifecycle listener as it reports directly from native level
1517
// ignoring native popups
16-
return FGBGLifecycle();
18+
return FGBGLifecycle(FGBGEvents.instance.stream);
1719
} else {
1820
// For Web and Desktop we use the WidgetObserver implementation directly from Flutter
1921
// TBF Flutter doesn't have a very reliable background signal for those platforms
2022
return WidgetObserverLifecycle();
2123
}
2224
}
2325

24-
final LifeCycle lifecycle = _getLifecycleStream();
26+
final LifeCycle lifecycle = getLifecycleStream();

packages/core/lib/utils/store/io.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// coverage:ignore-file
12
import 'dart:async';
23
import 'dart:convert';
34
import 'dart:io';

packages/core/pubspec.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@ dev_dependencies:
2929
build_runner: ^2.4.7
3030
flutter_test:
3131
sdk: flutter
32+
fake_async: ^1.0.0
3233
flutter_lints: ^4.0.0
3334
json_serializable: ^6.8.0
3435
pigeon: ^7.2.1
35-
mockito: ^5.4.4
36+
mockito: ^5.3.2
3637

3738
flutter:
3839
plugin:
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// test/analytics_platform_impl_test.dart
2+
import 'package:flutter_test/flutter_test.dart';
3+
import 'package:mockito/mockito.dart';
4+
import 'package:segment_analytics/analytics_pigeon.dart';
5+
6+
import 'package:segment_analytics/native_context.dart';
7+
import 'mocks/mocks.mocks.dart';
8+
9+
void main() {
10+
TestWidgetsFlutterBinding.ensureInitialized();
11+
12+
group('AnalyticsPlatformImpl Tests', () {
13+
late AnalyticsPlatformImpl analyticsPlatform;
14+
late MockNativeContextApi mockNativeContextApi;
15+
16+
setUp(() {
17+
mockNativeContextApi = MockNativeContextApi();
18+
analyticsPlatform = AnalyticsPlatformImpl();
19+
analyticsPlatform.api = mockNativeContextApi;
20+
});
21+
22+
test('getContext returns NativeContext', () async {
23+
final nativeContext = NativeContext();
24+
when(mockNativeContextApi.getContext(any))
25+
.thenAnswer((_) async => nativeContext);
26+
27+
final result = await analyticsPlatform.getContext(collectDeviceId: true);
28+
29+
expect(result, isA<NativeContext>());
30+
verify(mockNativeContextApi.getContext(true)).called(1);
31+
});
32+
});
33+
}
Lines changed: 92 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
import 'package:segment_analytics/analytics.dart';
22
import 'package:segment_analytics/analytics_platform_interface.dart';
3+
import 'package:segment_analytics/client.dart';
34
import 'package:segment_analytics/event.dart';
5+
import 'package:segment_analytics/flush_policies/count_flush_policy.dart';
6+
import 'package:segment_analytics/flush_policies/flush_policy.dart';
47
import 'package:segment_analytics/logger.dart';
8+
import 'package:segment_analytics/plugins/event_logger.dart';
59
import 'package:segment_analytics/state.dart';
610
import 'package:flutter/widgets.dart';
711
import 'package:flutter_test/flutter_test.dart';
812
import 'package:mockito/mockito.dart';
913
import 'package:shared_preferences/shared_preferences.dart';
1014

1115
import 'mocks/mocks.dart';
16+
import 'mocks/mocks.mocks.dart';
1217

1318
void main() {
1419
WidgetsFlutterBinding.ensureInitialized();
@@ -21,55 +26,118 @@ void main() {
2126
];
2227

2328
group("analytics", () {
24-
25-
setUp(() {
29+
late Analytics analytics;
30+
late MockHTTPClient httpClient;
31+
setUp(() async {
2632
AnalyticsPlatform.instance = MockPlatform();
27-
2833
// Prevents spamming the test console. Eventually logging info will be behind a debug flag so this won't be needed
2934
LogFactory.logger = Mocks.logTarget();
30-
3135
SharedPreferences.setMockInitialValues({});
32-
});
3336

34-
test(
35-
"it fetches settings but does not fire track event when not tracking lifecycle events",
36-
() async {
37-
final httpClient = Mocks.httpClient();
37+
httpClient = Mocks.httpClient();
3838
when(httpClient.settingsFor(writeKey))
3939
.thenAnswer((_) => Future.value(SegmentAPISettings({})));
4040
when(httpClient.startBatchUpload(writeKey, batch))
4141
.thenAnswer((_) => Future.value(true));
4242

43-
Analytics analytics = Analytics(
43+
analytics = Analytics(
4444
Configuration("123",
4545
trackApplicationLifecycleEvents: false,
46-
appStateStream: () => Mocks.streamSubscription()),
46+
token: "abcdef12345"),
4747
Mocks.store(),
4848
httpClient: (_) => httpClient);
4949
await analytics.init();
50+
});
5051

52+
test(
53+
"it fetches settings but does not fire track event when not tracking lifecycle events",
54+
() async {
55+
5156
verify(httpClient.settingsFor(writeKey));
5257
verifyNever(httpClient.startBatchUpload(writeKey, batch));
5358
});
5459
test(
5560
"it fetches settings and fires track event when tracking lifecycle events",
5661
() async {
57-
final httpClient = Mocks.httpClient();
58-
when(httpClient.settingsFor(writeKey))
59-
.thenAnswer((_) => Future.value(SegmentAPISettings({})));
60-
when(httpClient.startBatchUpload(writeKey, batch))
61-
.thenAnswer((_) => Future.value(true));
62-
63-
Analytics analytics = Analytics(
64-
Configuration("123",
65-
trackApplicationLifecycleEvents: true,
66-
appStateStream: () => Mocks.streamSubscription()),
67-
Mocks.store(),
68-
httpClient: (_) => httpClient);
69-
await analytics.init();
7062

7163
verify(httpClient.settingsFor(writeKey));
7264
verifyNever(httpClient.startBatchUpload(writeKey, batch));
7365
});
66+
67+
test('it analytics track should be callable', () {
68+
analytics.track("test track");
69+
});
70+
test('it analytics screen should be callable', () {
71+
analytics.screen("test screem");
72+
});
73+
test('it analytics identify should be callable', () {
74+
analytics.identify();
75+
});
76+
test('it analytics group should be callable', () {
77+
analytics.group("test group");
78+
});
79+
test('it analytics alias should be callable', () {
80+
analytics.alias("test alias");
81+
});
82+
test('it analytics cleanup should be callable', () {
83+
analytics.cleanup();
84+
});
85+
test('it analytics reset should be callable', () {
86+
analytics.reset();
87+
});
88+
test('it analytics addFlushPolicy should be callable', () {
89+
List<FlushPolicy> policies = [];
90+
policies.add(CountFlushPolicy(5));
91+
analytics.addFlushPolicy(policies);
92+
});
93+
test('it analytics getFlushPolicies should be callable', () {
94+
analytics.getFlushPolicies();
95+
});
96+
test('it analytics removeFlushPolicy should be callable', () {
97+
List<FlushPolicy> policies = [];
98+
policies.add(CountFlushPolicy(5));
99+
analytics.removeFlushPolicy(policies);
100+
});
101+
test('it analytics removePlugin should be callable', () {
102+
analytics.addPlugin(EventLogger(), settings: {"event":"Track Event"});
103+
});
104+
test('it analytics removePlugin should be callable', () {
105+
analytics.removePlugin(EventLogger());
106+
});
107+
test('it analytics onContextLoaded should be callable', () {
108+
analytics.onContextLoaded((p0) { });
109+
});
110+
test('it analytics onPluginLoaded should be callable', () {
111+
analytics.onPluginLoaded((p0) { });
112+
});
113+
114+
test("Test analytics platform getContext", () {
115+
AnalyticsPlatform analyticsPlatform = MockAnalyticsPlatform();
116+
117+
expect(
118+
() async => await analyticsPlatform.getContext(),
119+
throwsA(isA<UnimplementedError>()),
120+
);
121+
});
122+
test("Test analytics platform linkStream", () {
123+
AnalyticsPlatform analyticsPlatform = MockAnalyticsPlatform();
124+
125+
expect(
126+
() async => analyticsPlatform.linkStream,
127+
throwsA(isA<UnimplementedError>()),
128+
);
129+
});
130+
131+
test("it createClient", () async {
132+
Analytics analytics = createClient(Configuration("123",
133+
debug: false,
134+
trackApplicationLifecycleEvents: true,
135+
trackDeeplinks: true,
136+
token: "abcdef12345")
137+
);
138+
expect(analytics, isA<Analytics>());
139+
});
74140
});
75141
}
142+
143+
class MockAnalyticsPlatform extends AnalyticsPlatform { }

0 commit comments

Comments
 (0)