https://kotlinlang.org logo
#android-architecture
Title
# android-architecture
u

ursus

03/15/2020, 2:24 PM
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

Anastasia Finogenova

03/15/2020, 3:14 PM
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

ursus

03/15/2020, 4:19 PM
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

Anastasia Finogenova

03/15/2020, 4:22 PM
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

ursus

03/15/2020, 4:23 PM
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

Anastasia Finogenova

03/15/2020, 4:24 PM
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

ursus

03/15/2020, 4:25 PM
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

Anastasia Finogenova

03/15/2020, 4:26 PM
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

ursus

03/15/2020, 4:26 PM
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

Anastasia Finogenova

03/15/2020, 4:27 PM
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

ursus

03/15/2020, 4:27 PM
big issues with that, its way way way way slower, and basically a hack
a

Anastasia Finogenova

03/15/2020, 4:28 PM
I mean I have 3k tests and takes 4 sec to run how fast do you need them to run 🤷
u

ursus

03/15/2020, 4:28 PM
3k powermockito private method tests?
a

Anastasia Finogenova

03/15/2020, 4:29 PM
There is 50/50 but they run in a batch
I don't run them separately
u

ursus

03/15/2020, 4:29 PM
intereseting, for me theyve been extremely slow
a

Anastasia Finogenova

03/15/2020, 4:29 PM
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

ghedeon

03/15/2020, 7:49 PM
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).
2 Views