Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to selection of the constructor used in the mock class #115

Open
riQQ opened this issue May 14, 2024 · 3 comments
Open

Improvements to selection of the constructor used in the mock class #115

riQQ opened this issue May 14, 2024 · 3 comments

Comments

@riQQ
Copy link
Contributor

riQQ commented May 14, 2024

  • fallback to internal constructor if no public constructor is available
    This works, because the mock is in the same package as the mocked type.
  • use the primary constructor if available.
    This helps mocking classes with the Serializable attribute, as this creates another constructor that is sometimes chosen by Mockative, which leads to an error.
    This is a breaking change, so either needs a new version that allows breaking changes or has to be opt-in via a feature flag in the settings.

I have most of the code ready (minus the feature flag) and am willing to send a PR if this is accepted.

@Nillerr
Copy link
Collaborator

Nillerr commented May 16, 2024

Hi @riQQ!

Can you submit an example of the code you're having trouble with? I understand that the generated constructor of a @Serializable class can mess things up, but I'm struggling to understand when and how you would mock a @Serializable object anyway. Is this issue observed when mocking a class accepting something like a (serializable) configuration instance in its constructor?

Using an internal constructor could be done since we're generating code in the same module (package-private is not a thing in Kotlin)

riQQ added a commit to riQQ/mockative that referenced this issue May 19, 2024
…uctor is available

Fallback to internal constructor if no public constructor is available. Add a test that verifies mocking a class with only an internal constructor works.

Part of mockative#115
@riQQ
Copy link
Contributor Author

riQQ commented May 19, 2024

To verify a function on the class is called the expected number of times. Here's one example from the project I'm working on:

class StringMapChangesTest {
    @Mock private lateinit var change: StringMapEntryAdd

    @Test fun one() {
        change = mock(classOf<StringMapEntryAdd>())
        every { change.toString() }.returns("x")
        every { change.conflictsWith(any()) }.returns(false)

        val changes = StringMapChanges(listOf(change))
        val someMap = mutableMapOf("a" to "b")

        assertEquals("x", changes.toString())

        changes.applyTo(someMap)
        verifyInvokedExactlyOnce { change.applyTo(someMap) }

        changes.hasConflictsTo(someMap)
        verifyInvokedExactly(2) { change.conflictsWith(someMap) }
    }

    fun <R> verifyInvokedExactly(times : Int, block: () -> R): Unit = verify(block).wasInvoked(exactly = times)

    fun <R> verifyInvokedExactlyOnce(block: () -> R): Unit = verify(block).wasInvoked(exactly = 1)
}
@Serializable
@Mockable
data class StringMapEntryAdd(override val key: String, val value: String) : StringMapEntryChange() {

    override fun toString() = "ADD \"$key\"=\"$value\""
    override fun conflictsWith(map: Map<String, String>) = map.containsKey(key) && map[key] != value
    override fun applyTo(map: MutableMap<String, String>) { map[key] = value }
    override fun reversed() = StringMapEntryDelete(key, value)
    override fun isValid() = key.length <= 255 && value.length <= 255
}
@Serializable
sealed class StringMapEntryChange {
    abstract val key: String
    abstract override fun toString(): String
    abstract override fun equals(other: Any?): Boolean
    abstract override fun hashCode(): Int
    abstract fun conflictsWith(map: Map<String, String>): Boolean
    abstract fun applyTo(map: MutableMap<String, String>)
    abstract fun reversed(): StringMapEntryChange
    abstract fun isValid(): Boolean
}

kris098e pushed a commit that referenced this issue May 20, 2024
…uctor is available (#117)

Fallback to internal constructor if no public constructor is available. Add a test that verifies mocking a class with only an internal constructor works.

Part of #115

Co-authored-by: riQQ <3404787+riQQ@users.noreply.github.com>
@riQQ
Copy link
Contributor Author

riQQ commented May 31, 2024

@Nillerr any opinion on the primary constructor topic?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants