Cette tâche était assez intéressante. Comme pour tous mes projets, j’ai commencé par comprendre la portée et l’état de cette application.
J’ai décidé d’utiliser la structure d’architecture propre pour l’architecture de l’application. J’ai construit l’application dans ces étapes: UI -> Domain -> Data
.
Pour un projet à petite échelle comme celui-ci, j’ai conclu que l’utilisation de bibliothèques de gestion d’état pouvait être exagérée et j’ai opté pour ce que Flutter a fourni : ChangeNotifiers
et InheritedWidget
.
Structure
L’exemple de structure de ce projet est affiché ci-dessous :
integration_test/
|- app_test.dart
|- custom_finders_matchers.dart
|- detail_screen_test_cases.dart
|- home_screen_test_cases.dart
|
lib/
|- data
| |- entity_mapper.dart
| |- models
| |- data_sources
| |_repository_impl.dart
|
|- domain
| |- pokemon_entity.dart
| |_ repository_base.dart
|
|- presentation
| |- widgets
| | |_ widget_export.dart
| |
| |_ data_controllers.dart
| |_ data_provider.dart
| |_ detail_screen.dart
| |_ home_screen.dart
|
|- util
| |- colors.dart
| |- extensions.dart
| |- icon_util.dart
| |_util_export.dart
|
|_ main.dart
La couche de présentation se compose de tout le code lié à l’interface utilisateur, y compris la logique de l’interface utilisateur. Cette couche dépend de la couche Domaine.
La couche de domaine relie la couche de présentation et la couche de données. Étant donné que la couche de présentation n’est autorisée à communiquer qu’avec cette couche. Le référentiel de base, entity(PokemonEntity
), et les mappeurs d’entités sont définis ici. La PokemonEntity
est une classe de données simple qui contient des champs spécifiques liés à l’interface utilisateur. Il ne sait rien de ce à quoi ressemblent les données réelles provenant du serveur. Les classes de mappeur sont fournies pour mapper un modèle de données à une classe d’entité.
La couche de données contient toute la logique métier. C’est l’épine dorsale de toute tâche liée aux données. Il héberge des classes de données de modèle qui analysent les objets JSON, une implémentation du référentiel, une source de données et une source de données locale.
Le dossier util contient certains utilitaires utilisés dans les applications, comme les couleurs, les extensions, etc.
Forfaits utilisés
Les dépendances utilisées sont listées ci-dessous :
- Polices Google: Ce forfait est inclus pour utiliser Noto Sans police pour l’application.
- Miroiter: L’effet de chargement est géré par ce paquet.
- Équable: Fournit une implémentation facile de l’égalité basée sur la valeur de différents types d’objets.
- Flutter SVG: utilisé pour afficher les URL des images SVG du réseau.
- Soit une fléchette: Fournit un moyen transparent et efficace de gérer les erreurs.
- GraphQL: Utilisé pour interagir avec les API pokemon GraphQL. Cela inclut également un Ruche implémentation du stockage local.
Pour comprendre pourquoi graphql et dio sont inclus dans ce projet, descendez en appuyant sur ici
- Fournisseur de chemin:
- Dio: Utilisé pour interagir avec les API pokemon RESTful.
Pour comprendre pourquoi graphql et dio sont inclus dans ce projet, descendez en appuyant sur ici
- Fournisseur de chemin: Utilisé par le Ruche package pour obtenir un chemin de stockage local sur l’appareil.
Dépendances de développement
- Test d’intégration: Un package pour aider à exécuter des tests d’intégration sur de vrais appareils ou émulateurs.
- Cocktails sans alcool: Utilisé pour se moquer de certaines parties du code pour les tests unitaires.
Pourquoi la mise en œuvre de Graphql et Restful
Pourquoi les deux Dio
et GraphQL
implémenté dans la même application ? Vous vous demandez peut-être cela. La raison est simple : j’ai remarqué que pokemon avait un API graphql qui est encore en version bêta. Sur la base de mon expérience avec GraphQL et de la flexibilité qu’il offre, j’ai décidé de me lancer.
Tout s’est bien passé jusqu’à ce que je sois accueilli par une mauvaise nouvelle. J’ai essayé de tester mon application quelques jours après et j’ai été accueilli par un erreur de serveur en panne. À ce moment-là, j’ai rappelé le sage conseil de ne pas utiliser les ressources encore en bêta, du moins pour la production. Malgré ce défi, il y avait de la lumière au bout du tunnel.
Le projet a été structuré de manière flexible. Il permet de changer facilement de sources de données. Après avoir terminé la configuration de l’API REST, j’ai pensé qu’il serait cool de conserver les deux implémentations.
Pour passer des API REST aux API GraphQL, rendez-vous sur lib/main.dart
sur line 15
et remplacez le code par le code ci-dessous.
final dataSource = GraphQlDataSource();
Désormais, l’application utilise les données de l’API GraphQL.
Pour en savoir plus sur la flexibilité offerte par GraphQL, voici un article que j’ai écrit à ce sujet : Article GraphQL.
Essai
Il peut parfois être pénible d’écrire des tests. Ce fut une expérience douce-amère pour moi d’écrire ces cas de test, mais cela en valait la peine. Cependant, je crois que les tests font partie intégrante du développement logiciel. Je me fais un objectif d’écrire les deux tests unitaires et tests de widgets. D’autant plus, tests d’intégration sont même bien meilleurs que les tests unitaires et widgets.
Le test d’intégration garantit que plusieurs composants (widget, détenteurs d’état, référentiel) d’une partie complète ou importante de l’application fonctionnent ensemble comme prévu, contrairement au test unitaire et au test de widget qui garantissent que les composants/éléments individuels fonctionnent ensemble.
Je me suis concentré sur l’écriture de tests d’intégration pour l’application, c’est pourquoi les cas de test unitaires sont peu nombreux et aucun cas de test de widget. Le test d’intégration couvre une grande partie. Pour exécuter ce test d’intégration avec couverture, utilisez la commande ci-dessous.
flutter test integration_test/app_test.dart --coverage
J’ai écrit quelques cas de tests unitaires pour m’assurer GraphQlDataSource
et RepositoryImpl
travailler comme prévu. Pour exécuter ces scénarios de test avec couverture, utilisez la commande ci-dessous.
Merci d’avoir pris le temps d’examiner mon projet. J’espère que cet écrit vous donne les informations dont vous avez besoin lorsque vous parcourez la base de code.
GitHub
Voir Github