Karn / notify

Simplified notification construction and delivery for Android.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proposal: Mocking notifications

afollestad opened this issue · comments

In apps I tend to give notification creation responsibility to injectable interface that has a "Real" implementation. The interface is mocked in my tests.

I could see this being a very big use case for this library in addition to the already great convenience. Since you're using Kotlin, this could just be an companion object extension that could be a testImplementation dependency. Something like:

Notify.withMock(context)
   ...
   .show()

Internally, it would use Mockito or some internal class that isn't the real Android framework class.

This sounds like a great idea -- though I'm a little unsure about what the implementation would look like (My mocking knowledge is a little limited). Perhaps you can clarify or provide an example library which uses such an extension function?

It seems that you would have to use the .withMock(context) to differentiate between a real implementation and a mocked implementation. Does this not mean that you would have to have some sort of provider which wraps all the Notify.with(context) calls to automatically give you the correct instance of the library? Or is the assumption that the function call to build and show a notification is self-contained and we simply want to swap out this self-contained chunk with the corresponding mocked chunk?

I could definitely contribute if you'd like 😄

Since you have:

class Notify {
    companion object {
        fun with(context: Context): Notify {
            ...
        }
    }
}

You could have another module, a test module, that declares something like this:

fun Notify.Companion.withMock(context: Context): Notify {
    ...
}

I was thinking you could integrate with Mockito like this:

fun Notify.Companion.withMock(context: Context): Notify {
    return Mockito.mock(Notify::class.java)
}

However that wouldn't be automated and would require usage updates. So it would be nice if the existing with method could do this automatically, internally.

Maybe there could be some sort of global property that would be set when a unit test or UI test is beginning to run. With that property set to true, the existing with(Context) method could know to switch out the real implementation with a mock implementation.

I'm always taking new contributions! Your proposal makes sense to me and I think I would be very beneficial. If you can throw up a PR I can take a look and we can get it merged in.

Turns out that the if we want to mock the NotificationManager as well, we can simply supply the mocked instance as follows (provided that we are scoped in test sources due to the restriction imposed by the internal access modifier):

Notify.defaultConfig {
    notificationManager = mockNotificationManager
    ...
}

As long as this step is done during initialization, i.e prior to the first use of Notify.with(...), the mocked instance of the Notification Manager will be used. This takes care of external APIs that might need to be mocked.
Finally, I think the best solution would be to use a withMock(...) extension function, I would prefer not to add test specific conditional logic to the with(...) function.

Let me know what you think!