Git Product home page Git Product logo

kmock's Introduction

KMock

A humble mocking library for Kotlin, KotlinJS and Kotlin Multiplatform using Kotlin Symbol Processing (KSP).

Latest release License Platforms CI - Build Snapshot Version Coverage Quality Gate Status Reliability Rating CII Best Practices

About The Project

Writing mocks is certainly no witchcraft, but doing them by hand day for day can be dull. More importantly it takes time which can be better invested directly into writing tests. However, while JVM projects get indeed supreme support by either MockK or Mockito, Kotlin Multiplatform still has nothing comparable. KMock aims to fill that gap and will hopefully advance to there over time. Similar to other projects it uses KSP, but it is capable of associating generated Mocks correctly to their belonging shared source sets (like native, ios, etc) without additional setup and with minimal boilerplate done by consumers. KMock works currently only based on interfaces. It supports to some extent features like spying and relaxation of Mocks to make them non intrusive. So if the project caught your eye check out the Playground or dive into the Documentation.

Dependencies

KMock has the following dependencies:

Additional Requirements

  • Android 5.0 (API 21) to Android 13 (API 33)
  • Java 11

Changelog

See changelog.

Versioning

This project uses Semantic Versioning as a guideline for our versioning.

Contributing

You want to help or share a proposal? You have a specific problem? Read the following:

Releasing

Please take a look here.

Copyright and License

Copyright (c) 2024 Matthias Geisler / All rights reserved.

Please refer to the License for further details.

kmock's People

Contributors

bitpogo avatar

Stargazers

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

Watchers

 avatar  avatar

kmock's Issues

vararg eats specialised Array types and covariant types when inherited

Description

Currently the vararg workaround eats covariants and specialised.
Consider following:

interface A  {
    fun foo(vararg x: Array<out Any>)
    fun bar(vararg x: IntArray)
    fun <T> oo(vararg ozz: RRR<out T>): Any
}

interface B: A

Actual Behavior

class BMock(...): B  {
    ...
    fun foo(vararg x: Any) {...}
    fun bar(vararg x: Int) {...}
    fun <T> oo(vararg ozz: RRR<*>): Any {...}
   ...
}

Expected Behavior

class BMock(...): B  {
    ...
    fun foo(vararg x: Array<out Any>) {...}
    fun bar(vararg x: IntArray) {...}
    fun <T> oo(vararg ozz: RRR<out T>): Any {...}
   ...
}

Don't expose `kspy` needlessly

Description

Currently kspy is generated always. Even if it is just a minor issue, it would be nice if kspy is not generated at all when not in use.

Support Receivers

Description

Currently KMock generates Members for receivers normal members.

Acceptance Criteria:

  • Receiver member proxies are accessable like normal proxies
  • receiver members are generated as receivers not as normal members

Improve Plugin invocation

Description

The current mode of invocation is to error prone and should ideally come with minimum constraints.

Acceptance Criteria

  1. The plugin can be applies directly
  2. The extension has a handle to provide source precedence while confgured

Consider a DummyFactory for data classes

Description

Once KFixture has been progressed further and is ready to release a much easier support for relaxing will be possible.
However to prepare slowly for a probable plugin a first step should be to provide an entry point for data class dummies.

Acceptance Criteria

  1. The extension allows via feature flag to opt-in this behaviour but is disabled by default
  2. The extension or via Annotation picks up declared dummies
  3. The processor will generate a factory which supports project internal data classes in a limited scope (no generics for now)

Decouple BuildIns from Names

Description

Currently BuildIns are resolved by their name. Overloaded variants should be resolved nevertheless even if no BuildIns are set. However this is not the case at the moment.

Refactor Type Name resolver when overloaded

Description

Currently the prefixes of type names are filtered instead of allow listed.
This actually can cause unnecessarily boilerplate. The avoidance of collisions can be done when an error occurs by a consumer.

Acceptance Criteria:

  1. Add 2 new fields to the Extension - one as a feature flag/switch between the already implemented version and the new to avoid a breaking change. One for the allowList.

  2. Deprecated the existing flag.

  3. Processor implements the switch as well as the new behaviour for the FunctionGenerator/MethodGenerator

Handle mixed cases of Platform generics

Description

Currently platform factory methods for KMP always use expect/actual and do not respect platform only cases.

Acceptance Critera:

  • Factories for generics are using the appropriate modifier according if they implement a meta source or not.

TypeAliases causes Collisions with AccessMethods

Description

Since the AccessMethods depend on the SideEffect signature, they can be grouped wrongly if TypeAliases are in the mix.
This can cause an additional AccessMethod which collides with a correctly added Method.
Possible Fixes are:
Either use only the abbreviate type or it only when creating the keys for the AccessMethods.

Wrong ArtifactId

Description

The publishing of the GradlePlugin is slightly wrong configured.

Expected Behavior

<artifactId>kmock-gradle.gradle.plugin</artifactId>

Actual Behavior

<artifactId>tech.antibytes.kmock.kmock-gradle.gradle.plugin</artifactId>

Reduce noise

Description

Expected Behavior

Noise does not show up.

Actual Behavior

w: .../kmock-playground/example-js/build/generated/ksp/js/test/kotlin/tech/antibytes/kmock/example/MockFactory.kt: (28, 3): Parameter 'verifier' is never used
w: .../kmock-playground/example-js/build/generated/ksp/js/test/kotlin/tech/antibytes/kmock/example/MockFactory.kt: (29, 3): Parameter 'freeze' is never used
w: .../kmock-playground/example-js/build/generated/ksp/js/test/kotlin/tech/antibytes/kmock/example/MockFactory.kt: (30, 17): The expression is unused

Possible Fix

Simply apply @Suppress("UNUSED_PARAMETER") and @Suppress("UNUSED_EXPRESSION") file wide on factories.

Steps to Reproduce

Run ./gradlew check in the Playground

Allow custom Annotation for shared sources

Description

Currently KMock only supports definitions for shared sources via @MockShared.
While it is good enough for smaller projects it might not for middle sized or bigger once with many different sources. Custom Annotations can help here.

Acceptance Criteria:

  • The Extension allows definition of custom Annotations for shared sources.
  • The processor picks them up and hooks them in alongside with @MockShared.

Relaxation fails for Generics

Description

Currently Relaxation for Interfaces with generics causes an Compiler Error.
This only applies for inline functions. (The need additional arguments and cannot be inline in this case)

Allow multi interface mocks

Description

Currently only single interface mocks are allowed, but not the union of n-parents with n>1.
This could be "easily" done by also consuming Arrays via the already existing Annotations or via new Annotations (possibly the better way since it keeps the type system intact).

MultiBounded ParameterTypes are not resolved correcty

Description

Things like:

interface X {
    fun <T : Map<String, W>, W : G, G> foo(arg: T) where G : CharSequence?, G : Comparable<T>?
    fun <T : Map<String, W>, W : G, G> bar(vararg arg: T) where G : CharSequence?, G : Comparable<T>?
}

are resolved incorrectly with having the boundaries completely replaced W instead with Any.

Augment spyOn

Description

spyOn mostly adds to custom optimisation, but can be error prone and inconvenient. Therefore an additional flag to enableAll the spies might be a good addition to complement the selective approach.

Acceptance Criteria:

  • Add to the GradleExtension a flag and propagate the change to the processor which enables for all (applicable) Mocks Spies

vararg support

Description

Currently vararg is currently not supported, which it should.

Expected Behavior

interface Platform {
    fun bar(vararg buzz: Int)
}

should be:

internal class PlatformMock(
    ..
) : Platform {
   ..

    public val _bar: KMockContract.SyncFunProxy<Unit, (Array<Int>) -> Unit> = 
            
      ..

    public override fun bar(vararg buzz: Int) = _bar.invoke(buzz)

    ..
}

Actual Behavior

internal class PlatformMock(
    ...
) : Platform {
   ..

    public val _bar: KMockContract.SyncFunProxy<Unit, (Int) -> Unit> = 
            
      ..

    public override fun bar(vararg buzz: Int) = _bar.invoke(buzz)

    ..
}

Possible Fix

KSValueParameter has a isVararg property, which needs to be propagated starting from determineParameter.

MockShared is not generating classes correctly

Description

In my project, we have an extra source-set between common and the platform called mobile(Main/Test)
We use it to avoid exposing mobile-only classes to JS

Expected Behavior

When using @MockShared("mobileTest", MobileMainClass::class), it should generate the mock for the mobileTest source-set

Actual Behavior

The mock class is not being generated

image

Steps to Reproduce

  1. Download example project https://github.com/faogustavo/KMockExample
  2. Open the ViewModelTest class
  3. Try to run

Your Environment

  • Version used: Snapshot

Consider alternative Assertion pattern

Description

The current implemented Assertion feel wrong, aesthetically and and from the handling since they combine actual arguments and boundaries.

Consider instead doing:

assert(mock._someProxy) { hasBeenCalled().times(42) }

or

assert { mock._someProxy.hasBeenCalled().times(42) }

or similar.

This could be a better fit. Additionally this should deprecate the current Assertions and verify. Also consider a non breaking renaming of the current methods of the verifiers to fit the overall naming convention and since they currently act like assertions.

Make MockShared more convenient

Description

Currently MockShared needs the full SourceSet name, while only the prefix (eg. common) is sufficient.

Acceptance Criteria:

  • MockShared with only the prefix
  • MockShared with the complete name for test sources

Optimise the Processor

Description

The processor currently has (too) many loops. They can be reduced by using an emitter like approach and other micro optimisations.

Make freezing behaviour globally configurable

Description

Currently freeze is always true by default, which can harm the dev experience even if it is not needed.
Simple solution is to make it configurable via the Extension of the GradlePlugin.

Acceptance Criteria:

  • The GradleExtension has a new field, which is true on default but can be switched to false
  • this value gets propagated to the Processor which uses it as default for the factories.

Prohibit deceiving kspy for generics

Currently kspy is generated for kspy even if they are not enabled. While using them it will simply fails.

Acceptance criteria:

  • do not generate the deceiving factories

Add or Constraint

Description

Support alternative on Expectations on argument level for more convenience and readability.

Introduce spy-only-flag

Description

KMock primarily aims on an intrusive approach. While it supports spying, there is no possibility to deactivate the kmock completely. As discussed elsewhere, KMock should also support this kind of approach.

Acceptance criteria:

  1. Add a feature flag spyOnly, which is false on default.
  2. If this flag is true, the processor should not produce kmock, but enable all captured interfaces for spying.

AccessMethods can collide with Generics

Description

Currently things like:

interface Collision {
  fun <T : Something<K>, K> foo(arg: T)
  fun <T : Something<R>, R> bar(arg: T)
}

cause collisions since the Parameter are not entirely resloved.

Reflect nested types

Description

Currently nested types are not resolved, which can lead to collisions in JS and Native (but not JVM!!)

Move UnitRelaxer Logic into ProxyFactory

Description

Currently the Processor hardwires all the Relaxers into the Mocks. At least the UnitRelaxer can be invoked with the ProxyFactory.

Acceptance Criteria:
At least relaxVoidFunction is wired by the ProxyFactory.

Optional:
Find a way to make that for all relaxers and Spies, in order to improve testability.

Improve Generic MI-Mocks Factories

Description

Currently it is super hard to initialise Multi-Interface Mocks which are based on generic Interface(s), due to their special nature. Practical speaking it renders them useless.
This must be improved! For example using the MockType instead of the TemplateTypes.

Optimise Runtime

Description

The runtime is slower than it has to be.

Acceptance Criteria:

  • Move the freezing/non freezing behaviour on ProxyFactory level
  • Improve verifyOrder and verifyStrictOrder

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.