How to Build a fuel logger “Android App” Guided by Tests
I’m a great fan growing object oriented code guided by test. Therefore, I created a small application demonstrating domain modelling skill and test driven development.
Book References
Before I begin, I do have five book recommendations on how to modelling the domain and last two for unit testing:
- Practical Object Oriented Design in Ruby by Sandi Metz
- Domain Driven Design Quickly by Abel Avram and with Floyd Marinescu as managing editor.
- Growing Object Oriented Code Guided by Test by by Freeman and Price
- Art of Unit testing by Roy Osherove
- Working effectively with legacy code by Michael Feathers
Below is the rough requirement for the app to be used:
Should track fill-ups, mileage, and fuel consumption.
Just enter fuel per unit price, amount and odometer while you are at the pump.
The application will show you distance and average fuel consumption.
Tools Used:
- Gradle as build tool
- Android Studio as IDE
- Java as programming language
- CircleCI as CI
Testing Frameworks:
- Robolectric
- Espresso
- Mockito
Coding Coverage
- Jacoco
- CodeCov
Code Quality Measure
- Codacy
Requirement Breakdown
The idea of the fuel logger is to create a offline Android app using java where the user can:
- Can view metrics like Average consumption, Driving cost and Total Kms, Total amount costs, Total Fuel consumption upon opening application
- Can add a fuel log with mandatory fields like date, current odometer, fuel unit price, amount filling
- ̶C̶a̶n̶ ̶e̶d̶i̶t̶/̶d̶e̶l̶e̶t̶e̶ ̶a̶n̶y̶ ̶e̶n̶t̶r̶y̶ (not covering as part of this)
- Can see full log entries.
Start
I did tests on the FreeBSD operating systems. You can download the project:
git clone https://github.com/Manikkumar1988/FuelLogger.git
Now, you can run unit test
./gradlew test
Above command executes (shared) instrumented tests + unit tests on JVM.
Additionally, you can run UI (or Instrumented) test on device or emulator
./gradlew cAT
Above command executes (non-shared + shared) instrumented tests tests on Device/Emulator.
You can see more details of the implementation by looking at the project’s git homepage.
Intro to Instrumented test:
Identification of Dependent and How to inject dependency
First things first, as you start writing the unit testing for UI, question that will raise in our mind is how to mock the dependency of viewmodel within Fragments.
That being said, To get to into this level all your business logic should have been moved to viewmodel, your fragments or activity should be dumb enough to just bind the data or manipulate UI attributes (example visibility, enabled) based on data.
Complete Example:
As mentioned earlier, One great thing after Google IO 2018, you can now execute above test code on and off device/emulator without any code change, more about it here.
Object Modelling
Identified domain models are “FuelLogs”, “FuelLog”, “FuelDao”:
FuelLogs Composite of FuelLog, responsible for calculating stats on collection of FuelLog entities like average consumption, total distance, total fuel consumption, total amount since inception.
FuelLog An “Entity Object” having timestamp as identity and other attributes that makes sense to problem statement.
FuelDao The Data Access Object (DAO) to isolate the application/business layer from the persistence layer (usually a relational database, but it could be any other persistence mechanism) using an abstract API.
Relationship:
Let’s examine which of these are a more natural way of expressing our intent.
FuelLogs has a List of FuelLog objects or,
FuelLogs is a List of FuelLog objects.
In real world, driver would be having a book, having all entries entered in row wise. Similarly FuelLogs is equivalent to book, so we can conclude that FuelLogs has a list of FuelLog objects hence composite relation.
Also FuelLogs has one to many relationship with FuelLog.
Application Architecture
MVVM
- Passing Event Triggered from View to ViewModel
- Passing Event Triggered from background Operation to View
- Passing Event from Fragment to Activity or Vice Versa
are performed view ObservableList or MutableLiveData which are observable pattern.
And in the fragment/activity, need to observe for the event as below
Considerations
Few extension I would like to see is support for multiple vehicle, better way of calculation stats without loading full data, supporting multiple metrics, ability to skip the entry for stats computation.
This project is only used for studies using android developed by layman in the subject, and perhaps not one of the best implementations, techniques, and uses of the language.
I am always open to feedback, so free feel to let me know what you think in the comments below.