u

    ursus

    2 years ago
    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?
    Anastasia Finogenova

    Anastasia Finogenova

    2 years ago
    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

    2 years ago
    well mocking obviously, but its a pure function, it doesnt need mocking
    for example basically mapping data models to ui models in a viewmodel
    Anastasia Finogenova

    Anastasia Finogenova

    2 years ago
    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

    2 years ago
    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
    Anastasia Finogenova

    Anastasia Finogenova

    2 years ago
    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

    2 years ago
    right, but I see people doing something like
    object FooMapper : (Foo) -> Bar {
       override invoke ..
    }
    
    or
    
    class FooMapper {
       fun map(foo: Foo) : Bar
    }
    Anastasia Finogenova

    Anastasia Finogenova

    2 years ago
    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

    2 years ago
    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
    Anastasia Finogenova

    Anastasia Finogenova

    2 years ago
    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

    2 years ago
    big issues with that, its way way way way slower, and basically a hack
    Anastasia Finogenova

    Anastasia Finogenova

    2 years ago
    I mean I have 3k tests and takes 4 sec to run how fast do you need them to run 🤷
    u

    ursus

    2 years ago
    3k powermockito private method tests?
    Anastasia Finogenova

    Anastasia Finogenova

    2 years ago
    There is 50/50 but they run in a batch
    I don't run them separately
    u

    ursus

    2 years ago
    intereseting, for me theyve been extremely slow
    Anastasia Finogenova

    Anastasia Finogenova

    2 years ago
    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

    2 years ago
    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).