👨🏼‍💻Testing the modules of your MVVM + Clean Architecture Android project Part 1: Creating your app [Beginner]

Sabrina Cara
Huawei Developers
Published in
6 min readJun 10, 2022
Image Source: https://proandroiddev.com/navigation-events-in-mvvm-on-android-via-livedata-5c88ef48ee83

Hello guys, I am back, this time with an article series on testing your Android project. In this article series, we aim to create an Android project using MVVM + Clean Architecture (because duhh, who doesn’t anymore?). After we create the simple android application, we will perform testing on each module of the project, starting from UI tests, to unit testing in each module such as view models, use cases, etc.

Introduction

Testing is an extremely important part of any software development process as it teaches us to completely test the functionalities of our project under various circumstances and get an adequate response from each test case. However, another important part of a software development process, which in turn facilitates the testing process as well, is the whole development methodology itself. By this, I specifically mean the code quality, from best practices to architecture used. Speaking of architecture, we prefer using architectures that make it easier to code, scale and test your project. For these specific reasons, we decided to use MVVM + Clean Architecture.

Project Development

The first part of this article series is to actually create the project and prepare it for testing. The project we have created is a simple Movie Searching and Movie Detail display. In this project, you basically search for a movie and the results would be displayed in a Recycler View. Clicking on any item of the Recycler View would then direct us to the details of the movie we selected.

The technologies and concepts used in this project are:

  • Kotlin
  • Clean Architecture
  • MVVM
  • Dependency Injection (Hilt)
  • Navigation Component
  • Retrofit / REST API
  • Data / View Binding
  • Coroutines

As you might already know, in a Clean Architecture project, there are three general modules: app, data, and domain. Let's get into them.

App Module:

Our app module consists of a user interface, meaning the views (Activity / Fragment) and the View Models belonging to them. In this project, we have MovieSearchFragment and MovieDetailsFragment and their respective ViewModels.

Movie Search

Movie Search Fragment basically presents a Search View where the user can enter a keyword. Based on the keyword entered by the user, we call a Movie API where we pass the keyword and in return, get a list of Movies and their basic information.

Additionally, we include a Recycler View where we adapt all the results received from the API in the shape of a list with movies being represented as items.

The Search ViewModel simply invokes the use case and collects the results we get from the movie search.

Movie Details

The other view of the application is displaying the details of a certain movie we have previously clicked in the recycler view. Passing the id of the movie as an argument during the navigation from one fragment to another makes it possible to get make an API call with that id, which results in the movie’s details.

The Details ViewModel in turn does the invocation of the respective use case.

Domain Module:

The domain module is the inner layer of a project using Clean Architecture, containing all the business information and data modules.

From the ViewModules in the App module, we call the use cases in the domain module.

These use cases actually inject the respective repository interfaces and return the respective data modules, either Movies or MovieDetails data classes.

What are these data classes? They are actually the business logic of the project, containing data that is unlikely to change and encapsulating it so that it is safe and non-susceptible to the change we spoke about. They contain the result that our API calls give us.

How do we create them? Depending on the results we expect from the API call, we can actually automatically create them. When making an API call, you need a URL that you are going to use to make the call. When entering this full URL in a search engine, you would normally get the results in form of an unformatted JSON file. Copy this information and save it, because we will need it later.

In your Android Studio IDE, you open Settings and go to Plugins and download JSON to the Kotlin plugin. Then, in your domain module, you can right-click, click New file and then select the newly appeared option of JSON to Kotlin data class. Copy-paste the unformatted JSON file from the URL, format it, and then generate the automatic data class.

Kotlin to data class from JSON

Data Module:

In the data module, we have the implementation of the repositories, whose interfaces stand in the domain module.

Apart from that, we have the DataSources and their interfaces together with the RetrofitClient Interface which established the endpoints of the API call.

interface MoviesListDataSource {    
suspend fun getMoviesList(keyword: String): Movies
}
interface MovieDetailsDataSource {
suspend fun getMovieDetails(movieId: Int): MovieDetails
}

Well at this point, we have two main issues: How do use cases inject the repository interfaces? and How do we integrate the rest of the Retrofit service?

In order to explain both of these questions, it is enough for us to mention one simple term: Dependency Injection

Dependency Injection means providing the dependencies for a certain class instead of manually creating them, hence increasing code reusability, testing, and overall best practice.

I have included the dependency injections in the app module, and they consist of three modules:

Network Module, containing the Retrofit implementation:

Repository Module, containing the repository injections:

Usecase Module, containing the use-case injections:

Result

As a result of the above implementations, you can finally see a simple integrated project using the latest technologies that look as follows:

Right now, we have a proper, simple project that we can test. In the upcoming article, we will test use cases and their behaviors. Stay tuned!

Tips & Tricks

  • Before you start the project, read about Clean Architecture / MVVM / Dependency Injections, etc., don’t jump to coding or you will end up copy-pasting without understanding anything.
  • Don’t forget to integrate the necessary dependencies in the gradle file
  • Don’t forget to add @AndroidEntryPoint and @HiltViewModel before each fragment and view model, respectively.
  • Don’t forget to generate your data classes automatically using the plugin presented previously
  • The network component is a SingletonComponent class while the other dependency injection models are ActivityRetainedComponent

Conclusion

In this article series, we aim to show testing methodologies in all the separate modules of a project developed using Clean Architecture + MVVM and many other new technologies. However, in order to test each module of this project, we first had to create the project and make it functional. In the next article, you will know how to create use case tests. Until then, stay healthy, stay amazing. See you soon friends!

References

--

--

Sabrina Cara
Huawei Developers

Android Developer at Huawei, HMS and Android enthusiast.