customerio / customerio-flutter

Flutter plugin for Customer.io
https://www.customer.io/docs/sdk/flutter/getting-started/
MIT License
12 stars 10 forks source link

Refactor CustomerIO class to Enable Dependency Injection, Better Testing, and Flexibility #84

Open AristideVB opened 1 year ago

AristideVB commented 1 year ago

Description:

The current design of the CustomerIO class relies on static methods, making it difficult to write unit tests and achieve Dependency Injection. Converting static methods to instance methods will make the class more testable and flexible.

Proposed Changes:

  1. Convert static methods in CustomerIO to instance methods.
  2. Continue to use the existing private constructor const CustomerIO._(); to ensure that CustomerIO remains a singleton.

This approach will maintain the singleton behavior while offering greater flexibility for testing and modularization.

Example:

Before:

// Using static method
CustomerIO.subscribeToInAppEventListener(_handleInAppEvent);

After:

// Using instance method through singleton
final customerIO = CustomerIO.instance;
customerIO.subscribeToInAppEventListener(_handleInAppEvent);

Practical Example with InAppMessagesBloc:

Suppose you have an InAppMessagesBloc that handles incoming in-app messages. In the current architecture, mocking CustomerIO for testing the Bloc is difficult.

Before:

class InAppMessagesBloc extends Bloc<InAppMessagesEvent, InAppMessagesState> {
  InAppMessagesBloc() : super(InAppMessagesInitial()) {
    on<InAppMessagesEventReceived>(_onInAppMessagesEventReceived);

    _inAppMessageStreamSubscription =
        CustomerIO.subscribeToInAppEventListener(_handleInAppEvent);
  }

  late StreamSubscription<dynamic> _inAppMessageStreamSubscription;
 // ...
}

After:

With the proposed changes, we can inject a mock or stubbed CustomerIO instance into the InAppMessagesBloc for better unit testing.

class InAppMessagesBloc extends Bloc<InAppMessagesEvent, InAppMessagesState> {
  InAppMessagesBloc(CustomerIO customerIO) : super(InAppMessagesInitial()) {
    on<InAppMessagesEventReceived>(_onInAppMessagesEventReceived);

    _inAppMessageStreamSubscription =
        customerIO.subscribeToInAppEventListener(_handleInAppEvent);
  }

  late StreamSubscription<dynamic> _inAppMessageStreamSubscription;
 // ...
}

Benefits: