How do you pass in your mappers to view models or ...
# android-architecture
u
How do you pass in your mappers to view models or wherever? Are they just toplevel functions? Or objects extending a function? Do you pass them in via a ctor or use directly?
a
If you pass something through the constructor it makes it easier to inject a mock and stub the behavior for testability purposes. But you can find workarounds of course for testing if you make them just instance reference. Extension functions are also an option if you do a lot of transformations on a particular type of inject in your app
u
well mocking obviously, but its a pure function, it doesnt need mocking
for example basically mapping data models to ui models in a viewmodel
a
So you question is not clear then If you have a function why do you need to "pass" it
Usually mapper is a stand alone class
So you either make it static or create an instance of that mapper
u
I know my options, im discussing design. i.e. wondering why a mapper needs to be a class? when it just maps, i.e. a pure function (T) -> R
a
I doesn't, it can be an extension function or a function inside Viewmodel itself or an Interactor if you have one
If you need to reuse it then you may need to have it in another class so you don't duplicate code
u
right, but I see people doing something like
Copy code
object FooMapper : (Foo) -> Bar {
   override invoke ..
}

or

class FooMapper {
   fun map(foo: Foo) : Bar
}
a
Maybe there is another opinions, let's wait. But mine is make is either extension fun to be reusable or just keep in your viewmodel/interactor. People do a lot of different things. I don't see any advantage in this approach if this logic is only local for one screen
u
and even if so, why should this be a view model constructor dependency? isnt it just a "externalized" function? its never going to be mocked
well, one advantage would be testing, if its private in your vm then no such luck, and extensions can work, unless youre mapping 2 sources into 1
a
Well sometimes you wanna stub what it returns for that flexibility you need to replace it with a mock
Private fun can be tested with powermockito
No issues with that
u
big issues with that, its way way way way slower, and basically a hack
a
I mean I have 3k tests and takes 4 sec to run how fast do you need them to run 🤷
u
3k powermockito private method tests?
a
There is 50/50 but they run in a batch
I don't run them separately
u
intereseting, for me theyve been extremely slow
a
I wouldn't call them way way way slower, a bit slower as there is more work of course with reflection
I don't know maybe you need to check what can be causing that other then power mockito itself, like your studio settings/machine specs. But even if you don't want to be testing private methods. Creating a local mapper object will not add testability with regular tools mockito/junit
You can't replace local variables with mocks and verify the mapper's output. You can use some workaround like argument captors or just revify that the value in your lifedata after mapping is expected for example
So you just verify if the UI data was updated with expected value basically and do it blackbox
g
if it's a simple mapper than sure, extension function is enough. But sometimes mappers have dependencies, like formatters, locales, app settings and what not. Feeding all of this to your pure function might be cumbersome, so logically, people make mappers part of the DI graph (if required).