article banner

Exercise: Mocking library

Your task is to implement a simple library for interface mocking. You should only support mocking interface methods that do not throw exceptions. This is how you should use it:

data class User(val name: String) interface UserRepository { fun getUser(userId: String): User? fun allUsers(): List<User> } interface UserService { fun getUser(): User } fun main() { val registry = MockRegistry() val userRepository = registry.mock<UserRepository>() val userService = registry.mock<UserService>() registry.setReturnValue( { userRepository.getUser("alex") }, User("Alex Smith") ) registry.setReturnValue( { userRepository.getUser("bell") }, User("Bell Rogers") ) registry.setReturnValue( { userRepository.getUser("dan") }, null ) registry.setBody({ userRepository.allUsers() }) { listOf(User("James Bond"), User("Jane Doe")) } registry.setBody({ userService.getUser() }) { User(userRepository.getUser("dan")?.name ?: "Unknown") } println(userRepository.getUser("alex")) // User(name=Alex Smith) println(userRepository.allUsers()) // [User(name=James Bond), User(name=Jane Doe)] println(userRepository.getUser("bell")) // User(name=Bell Rogers) println(userService.getUser()) // User(name=Unknown) registry.setReturnValue( { userRepository.getUser("dan") }, User("Dan Brown") ) println(userService.getUser()) // User(name=Dan Brown) }

Your implementation should use Proxy from the java.lang.reflect package.

You can find unit tests and usage examples in the MarcinMoskala/kotlin-exercises project on GitHub in the file advanced/java/Mocking.kt. You can clone this project and solve this exercise locally.

Hints:

  • A mocked method can be called to both record and use the mock. To know what situation it is, define a recording flag in your class.
  • Each call is identified by three things: mock object identifier, method name, and method arguments. You can define a data class to keep those three things.

Once you are done with the exercise, you can check your solution here.