Coder Social home page Coder Social logo

karmok's Introduction

Karmock

Karmok consists of an intelliJ plugin and a supporting library dependency which can help you manage interfaces in your unit tests for a KMP project. It is currently experimental and is not our vision for a complete KMP mocking solution, but it is definitely helpful for now.

Karmok allows you to generate a mock implementation of an interface which is capable of verifying method calls and overriding their results.

Pre-alpha

Karmock is a library used by Touchlab as an experimental tool. It's meant as an internal tool, as well as an experiment to find out what could go into a full fledged Kotlin Multiplatform mocking solution. We are simply making it public to show how a kmp mocking solution could work. If you decide to use Karmock, know that Touchlab is not providing any technical support for this library.

Limitations

Currently Karmock has a few limitations which should be mentioned here:

  • There is no concept of spies in Karmok.
  • The library only supports Interfaces
  • The IDE plugin is not in the marketplace, so you get it from the release section or build it yourself
  • Boilerplate is added to your code by the plugin when creating a mock

There is no guarantee that these limitations will change, as mentioned earlier this is an pre-alpha experimental tool

Installation

karmok-library

The library includes all the plumbing code which performs the recording and configuration of your mocks. Code generated by the plugin will expect this library to be present.

implementation(“co.touchlab:karmok-library:0.1.7”)

idea-plugin

This is the plugin which will generate mock implementations for you . To test, go to 'Tasks > intellij > runIde'. You'll need to create a project, or import an existing one. You'll need to add the mavenLocal repo and add the library dependency to use the generated mocks.

To use the plugin, create a class that implements an interface. Option+Enter on the class name and you should see "Implement Mock Members". Select the members you want to include (which should be all, but still).

pop up

You can import the plugin using the zip from the releases section on GitHub, using intellij's settings pane. Alternatively you can build the plugin with 'buildPlugin', which makes a zip in 'build/distributions'.

import

Usage

Say we want to create a mock implementation for the following interface:

interface MyInterface {
    val name: String
    fun hey(): Long
}

The first step will be to create an empty class with the interface in it’s signature

class MockMyInterface: MyInterface {

}

The IDE will complain that MockMyInterface doesn’t implement the necessary methods to fulfill MyInterface. Rather than write them ourselves, we will use the Karmok plugin to fill in the class. Press Option+Enter on the class name to open the quick fix dialog. In the list you should see “Implement Mock Members”. Select all the members and press ok to generate the body The intellij plugin will add implementation inside TestingImpl

class MockMyInterface: MyInterface {
    internal val mock = InnerMock()
    override val name: String by mock.name
    override fun hey(): Long {
        return mock.hey.invoke({ hey() }, listOf())
    }

    class InnerMock(delegate: Any? = null) : MockManager(delegate) {
        internal val name = MockPropertyRecorder<TT, String>({ name }) {}
        internal val hey = MockFunctionRecorder<TT, Long>()
    }
}

The implementation includes an inner class called InnerMock, which extends MockManager. Each function and property of the interface gets a Recorder instance in InnerMock. These classes are included in the karmok-library dependency which must be present. The recorders can be configured with what to be returned when called, and can be verified after you are done with interaction.

@Test
fun helloTest(){
    val tt = MockMyInterface()
    tt.mock.name.returnOnCall("touchlab")
    tt.mock.hey.returns(22L)
    
    assertEquals(tt.hey(), 22L)
}

There are 2 recorders, MockFunctionRecorder and MockPropertyRecorder. I've added a set of interfaces for each that are focused on config and verify operations. For example, for properties:

interface MockPropertyConfigure<RT> {
    fun throwOnCall(t: Throwable)
    fun returnOnCall(rt: RT)
}

interface MockPropertyVerify<RT> {
    val getCalled: Boolean
    fun setCalled(rt: RT): Boolean
    val calledCountGet: Int
    val calledCountSet: Int
}

These are separate because the next goal was to improve the config and verify steps, but that is incomplete. It would look something like the following:

@Test
fun helloTest(){
    val tt = MockMyInterface()
    tt.mock.config {
        name.returnOnCall("touchlab")
        hey.returns(22L)
    }
    
    assertEquals(tt.hey(), 22L)
    
    tt.mock.verify {
        assertEquals(hey.calledCount, 1)
    }
}

Not implemented, but that's why there are multiple interfaces. Currently, the config and verify functions can feel a little confusing because they both show up on autocomplete, but you'll probably get used to it.

Issues

Currently the plugin does not add the imports for the inserted plumbing code. This is technically not too difficult, but it's also not super critical. To add later.

karmok's People

Contributors

kevinschildhorn avatar kpgalligan avatar samhill303 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

dalewking

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.