Unit Testing Object Classes


#1

Hey All,

I’ve been struggling real hard to come up with a reliable way to unit test Kotlin’s Object Classes (https://kotlinlang.org/docs/reference/object-declarations.html).

I tried using MockK Library as well but it ends up calling actual method on Object class instead of mocking it. I will keep investigating this part though meanwhile.

However, my main question being, is there any real way to unit test Object class without using MockK Library to begin with?

Just for context, I have two Object classes where class A is calling another Object class B and I am trying to write unit tests for Class A and is in need of mocking Class B.


#2

Just to be clear, your problem is not really Unit testing object classes as much as it is mocking object classes in you unit tests, correct?

Seems to me that this issue is not specific to object classes at all. Rather, you would have this problem if your unit under test depended on any non-open class, that it refers to directly.

A common solution to this problem is to declare interfaces for all classes that need to be mocked and use dependency injection whenever one class depends on another.

Remember that object classes can implement interfaces and be passed as arguments to methods and constructors.


#3

Thanks for response. Testing non-open classes works just fine (i.e. regular kotlin classes since they are final by default) but testing/mocking Object classes seems to have issues as it ends up calling no matter what.

Declaring interface just for the purpose of mocking seems to harsh and seems unnatural to do so. Why to clutter production code with unwanted interfaces when I just want to declare some object classes to host utility methods.

Isn’t there any other approach that avoids such work arounds? Mockk library seems to be for that very purpose but I am trying to get it working. But was wondering what everyone else uses generally to mock Object class dependency?


#4

Seems like your problem is testing singletons. Which is always the problem with testing singleton. I would more look into how you could avoid using the object declaration to make you code more stateless and pure.


#5

May be I should ask this: Is there a better way to creating a class in kotlin that allows us to group utility methods? which is similar to what we might do in java where a class has private constructor and bunch of static methods.


#6

Then yes that’s a different question altogether. Here is yole he is kotlin tool team lead, dev slides https://www.slideshare.net/intelliyole/idiomatic-kotlin and his presentation on language idioms and here is the video https://youtu.be/ZWuq1AM-XHc?t=9m31s

But the general answer is you should not be using singletons to create utility class like in java. Utility classes aren’t a thing in kotlin. You should use extension functions that are scoped to were they will be used or top-level functions.


#7

This helps. Thanks very much!


#8

@Radzell, I tried making use of top level functions to create utility methods. However, I am facing the same issue wherein I am unable to mock the method call for this top level functions from the caller class. since there is no enclosing class, I can’t even mock it using static class or that access the class as there is not enclosing class to begin with. Googling didn’t help either.

my utility function is not straightforward, meaning the call has to be mocked otherwise errors will be thrown.

Do you have any idea on how I can mock top level functions ? Appreciate your answer.


#9

If the functions are utility methods, you need to be extremely careful mocking them. In many cases mocking those methods will mean that you are testing implementation details of the actual unit under test. If utility functions are stateless just make sure that you first test those. If they have state, they probably shouldn’t be utility functions. Once they are working don’t attempt to mock them, just use the proper implementation. If they work on a state object, mock that object rather than the utility function.

From my perspective a unit test testing more code is only really a problem if it leads to a cascade in errors where the complexity of the state is such that it becomes hard to know what is tested, or if the test fails what part of it failed. Another issue could be that two bugs “cooperate” to mask a bug. If you allow higher level to lower level delegation to actual code (and make sure to test the lower level functionality independently - lower level means it doesn’t depend on the higher level) then you safe yourself a lot of mocking work and are actually able to much easier have realistic tests of the lower level code (a failure there should lead to a failure overall).


#10

I’d have to see the code. You could pass in the function as a parameter and use a default parameter for the function you’d use in prod.