- This project is following the Flutter TDD Clean Architecture Course by Reso Coder
- The course teaches how to build a Flutter app using Test Driven Development (TDD) and Clean Architecture principles
This course teaches you how to build a Flutter app using Test Driven Development (TDD) and Clean Architecture principles. You will learn how to write testable and maintainable code, how to structure your app into layers of abstraction, and how to implement features such as caching, connectivity, and error handling.
Video 1: Explanation & Project Structure
- Learn the core concepts of clean architecture and how it applies to Flutter
- Create a Flutter project with clean_architecture_tdd_course as the name
- Add dependencies for flutter_test, cupertino_icons, and pedantic
- Add .gitignore file with rules for Flutter and Dart
- Create a lib folder with main.dart file
- Create a test folder with widget_test.dart file
- Create folders for presentation, domain, and data layers inside lib
Video 2: Entities & Use Cases
- Create a core folder inside lib with error and usecases subfolders
- Create a Failure class in the core folder
- Create an abstract UseCase class with a call method in the usecases subfolder
- Create a features folder inside lib with number_trivia subfolder
- Create a domain folder inside number_trivia with entities and usecases subfolders
- Create a NumberTrivia class in the entities subfolder
- Create abstract classes for NumberTriviaRepository, GetConcreteNumberTrivia, and GetRandomNumberTrivia in the usecases subfolder
Video 3: Domain Layer Refactoring
- Learn about callable classes in Dart
- Refactor the
GetConcreteNumberTrivia
class to use thecall
method - Add another use case:
GetRandomNumberTrivia
- Create a
UseCase
base class to enforce a stable interface for all use cases
Video 4: Data Layer Overview & Models
- Learn about the data layer and its components: models, data sources, repositories
- Create a data folder inside number_trivia with models subfolder
- Create a NumberTriviaModel class that extends NumberTrivia entity
- Implement toJson and fromJson methods for NumberTriviaModel
- Write unit tests for NumberTriviaModel
Video 5: Contracts of Data Sources
- Learn about contracts of data sources and why they are useful
- Create data sources subfolder inside data with local_data_source.dart and remote_data_source.dart files
- Define abstract classes for NumberTriviaLocalDataSource and NumberTriviaRemoteDataSource with methods for getting trivia by number or randomly
- Write unit tests for data sources contracts
Video 6: Repository Implementation
- Learn about repository implementation and its role in the data layer.
- Implement NumberTriviaRepositoryImpl class that extends NumberTriviaRepository abstract class from domain layer.
- Inject local and remote data sources as dependencies into repository constructor.
- Implement getConcreteNumberTrivia and getRandomNumberTrivia methods using data sources and network info.
- Write unit tests for repository implementation.
Video 7: Network Info
- Learn about network info and how to check internet connection status in Flutter
- Add dependencies for connectivity package and mockito package
- Create network_info.dart file inside core folder with NetworkInfo abstract class and NetworkInfoImpl class that implements it
- Inject Connectivity as a dependency into NetworkInfoImpl constructor
- Implement isConnected method using Connectivity package methods
- Write unit tests for network info
Video 8: Local Data Source
- Learn about local data source and how to use shared preferences in Flutter
- Add dependencies for shared_preferences package
- Implement NumberTriviaLocalDataSourceImpl class that extends NumberTriviaLocalDataSource abstract class from data sources contracts
- Inject SharedPreferences as a dependency into local data source constructor
- Implement getLastNumberTrivia and cacheNumberTrivia methods using shared preferences methods
- Write unit tests for local data source
Video 9: Remote Data Source
- Learn about remote data source and how to use http package in Flutter
- Add dependencies for http package and http_mock_adapter package
- Implement NumberTriviaRemoteDataSourceImpl class that extends NumberTriviaRemoteDataSource abstract class from data sources contracts
- Inject HttpClient as a dependency into remote data source constructor
- Implement getConcreteNumberTrivia and getRandomNumberTrivia methods using http package methods and NumberTriviaModel.fromJson method
- Handle exceptions and errors from http requests
- Write unit tests for remote data source using http_mock_adapter package
Video 10: Bloc Scaffolding & Input Conversion
- Learn about bloc scaffolding and input conversion in the presentation layer
- Generate a number_trivia bloc subfolder with bloc extension
- Define abstract classes for NumberTriviaEvent and NumberTriviaState with equatable package
- Define subclasses for NumberTriviaEvent: GetTriviaForConcreteNumber and GetTriviaForRandomNumber
- Define subclasses for NumberTriviaState: Empty, Loading, Loaded, Error
- Inject GetConcreteNumberTrivia and GetRandomNumberTrivia use cases as dependencies into bloc constructor
- Wire up on method to handle TriviaForConcreteNumber and GetTriviaForRandomNumber events
- Create input_converter.dart file inside core folder with InputConverter class that converts a string to an unsigned integer or a failure
- Inject InputConverter as a dependency into bloc constructor
- Use InputConverter to validate and convert the input string before calling the use cases
Video 11 : Bloc Implementation 1/2
- Implement NumberTriviaBloc class that extends Bloc<NumberTriviaEvent, NumberTriviaState> abstract class from presentation layer contracts
- Inject GetConcreteNumberTrivia and GetRandomNumberTrivia use cases as dependencies into bloc constructor
- Implement on and on methods using use cases and InputConverter
- Handle failures and successes from use cases and emit appropriate states
- Write unit tests for bloc using mocktail package
Video 12: Bloc Implementation 2/2
- Learn how to use bloc_test package to simplify bloc testing
- Refactor bloc tests using blocTest function and expect states
- Implement NumberTriviaCubit class that extends Cubit abstract class from presentation layer contracts
- Inject GetConcreteNumberTrivia and GetRandomNumberTrivia use cases as dependencies into cubit constructor
- Handle failures and successes from use cases and emit appropriate states
- Write unit tests for bloc using blocTest function and expect states
Video 13: Dependency Injection
- Learn about dependency injection and how to use get_it package in Flutter
- Register all the classes and contracts as singletons or factories using GetIt methods
- Inject DI into
main()
before running application.
Video 14: Finishing the App
- Learn how to use Placeholder widgets to design the UI layout
- Create NumberTriviaPage widget and use BlocProvider, BlocBuilder, and BlocListener widgets
- Implement TriviaDisplay, MessageDisplay, LoadingWidget, TriviaControls widgets
- Create NumberTriviaPage widget and use Scaffold, AppBar, and Column widgets
- Implement MessageDisplay, LoadingWidget, and TriviaDisplay widgets using Container, Text, CircularProgressIndicator, and SingleChildScrollView widgets
- Use MediaQuery to set the height of the widgets according to the screen size
- Extract the widgets into their own files and use barrel files to simplify imports
- Implement TriviaControls widget using TextField, RaisedButton, and BlocConsumer widgets
- Dispatch GetTriviaForConcreteNumber and GetTriviaForRandomNumber events from the TriviaControls widget
- Wrap the body of the Scaffold with a SingleChildScrollView to prevent overflow when the keyboard appears
This course teaches you how to build a Flutter app using Test Driven Development (TDD) and Clean Architecture principles. You will learn how to write testable and maintainable code, how to structure your app into layers of abstraction, and how to implement features such as caching, connectivity, and error handling. By following this course, you will be able to build high-quality Flutter apps that are easy to maintain and extend.