DEV Community

Cover image for How to unit test a private method in Kotlin without making it public
Tristan Elliott
Tristan Elliott

Posted on • Edited on

How to unit test a private method in Kotlin without making it public

Table of contents

  1. The problem I am facing
  2. Why not make it public?

My app on the Google play store

My app's GitHub code

The problem I am facing

  • I have a relatively simple method that I want to test but its private. Why test it in the first place? Well, despite its simplicity it is very important to the project and I want the to be able to test it and ensure that it will run how I want it to. Even if myself or others change it. Further more, if the test fails it will be a sign to me that something has gone wrong and it needs to be fixed before the next release.

  • The function I want to test:

class TwitchEmoteImpl @Inject constructor(
    private val twitchEmoteClient: TwitchEmoteClient,

): TwitchEmoteRepo {

// THE FUNCTION I WANT TO TEST
private fun createMapValue(
    emoteValue: EmoteNameUrl,
    innerInlineContentMap: MutableMap<String, InlineTextContent>
){
    val url = emoteValue.url
    val value = InlineTextContent(
        Placeholder(
            width = 35.sp,
            height = 35.sp,
            placeholderVerticalAlign = PlaceholderVerticalAlign.Center
        )
    ) {
        AsyncImage(
            model = url,
            contentDescription = stringResource(R.string.moderator_badge_icon_description),
            modifier = Modifier
                .fillMaxSize()
                .padding(2.dp)
        )
    }

    innerInlineContentMap[emoteValue.name] = value

}
}
Enter fullscreen mode Exit fullscreen mode
  • The obvious question is, how do I test a private method without making it public?. The answer is, Dependencies!!!!!
  • To clarify, we take all of the logic out of this private method, put it into a public dependency that we can then test. Our updated code will look like this:
class TwitchEmoteImpl @Inject constructor(
    private val twitchEmoteClient: TwitchEmoteClient,
    private val emoteParsing:EmoteParsing = EmoteParsing()

): TwitchEmoteRepo {
 private fun createMapValue(
        emoteValue: EmoteNameUrl,
        innerInlineContentMap: MutableMap<String, InlineTextContent>
    ){
// WE CAN NOW UNIT TEST THE EmoteParsing CLASS
        emoteParsing.createMapValueForComposeChat(
            emoteValue,
            innerInlineContentMap
        )

    }

}

Enter fullscreen mode Exit fullscreen mode
  • As you can see the dependency (emoteParsing) we created is literally just a clone to help us aid in testing:
class EmoteParsing {

     fun createMapValueForComposeChat(
        emoteValue: EmoteNameUrl,
        innerInlineContentMap: MutableMap<String, InlineTextContent>
    ){
        val url = emoteValue.url
        val value = InlineTextContent(
            Placeholder(
                width = 35.sp,
                height = 35.sp,
                placeholderVerticalAlign = PlaceholderVerticalAlign.Center
            )
        ) {
            AsyncImage(
                model = url,
                contentDescription = stringResource(R.string.moderator_badge_icon_description),
                modifier = Modifier
                    .fillMaxSize()
                    .padding(2.dp)
            )
        }

        innerInlineContentMap[emoteValue.name] = value

    }
}

Enter fullscreen mode Exit fullscreen mode
  • We can now unit test this createMapValueForComposeChat() function through the EmoteParsing class.

Why not just make it public?

  • You obviously could make the method public. However, this would give developers(myself or others) the ability to use the code not as it was intended to. Essentially, increasing the scope of the class. By keeping the method private we are establishing clear boundaries between classes and leave smaller possibilities of misuses.

Conclusion

  • Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on Twitter.

Top comments (0)