Android Best Practice: Mocking Fragments vs. Using Separate UI Models?

I have a design pattern question regarding apollo-kotlin on Android, specifically about the best way to structure data for the UI layer (Jetpack Compose) to allow for easy testing and previews.

There seem to be two common approaches, and I’m trying to understand the trade-offs and recommended practice.

Approach 1: Use Generated Fragment Models Directly in the UI
The idea is to have a Composable depend directly on a GraphQL fragment model. The challenge here seems to be creating mock instances of GraphQLFragment for tests and Jetpack Compose @Previews.

Approach 2: Use Separate, Custom Models for the UI Layer The idea is to have the data layer map the Apollo-generated models to simple, custom data classes. The Composable then depends on this clean UI model.
This makes mocking for previews and tests trivial, but it adds a mapping layer and some boilerplate.

My Core Question:

What is the more scalable and maintainable approach in the long run?

Is it better to figure out an idiomatic way to mock the generated fragment models directly, or is it standard practice to decouple the UI with its own model layer?

I’d appreciate any insights on the pros and cons you’ve encountered with either pattern.

Thanks!

1 Like

Hi :waving_hand:

Thanks for the interesting question!

This has indeed been a recurring question over the years and I can only answer with my personal view on this as I don’t think there is a strong consensus on the best path here.

Traditionally, mobile apps architecture have adopted a clear separation of concerns and therefore recommended avoiding leaking your network models in your UI code (solution 2.).

Recently, we have seen more and more people using generated models directly in the UI (solution 1.) but the library wasn’t designed for this initially and this comes with some friction. We have ideas about things to improve there but it’s still the early days. You can follow Megaissue: jetpack compose and architecture · Issue #6147 · apollographql/apollo-kotlin · GitHub for tracking.

Overall, if you value consistency and battle tested solutions, I would say go for 2. If you’re more curious and eager to try more (potentially changing) solution, go for 1.

This is obviously my personal opinion. Maybe others in the community can chip in with their own experience.

2 Likes

Is there any way to mock fragments to use them in the Preview without defining all fields, only the necessary ones?

No easy way at the moment, sorry.

Fragments in general need to be in the context of an operation so something like apollo-kotlin-faker cannot execute them. What values would you expect in the “unnecessary fields”?

At least null for nullable fields

1 Like