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

Var property's behaviour is not getting set #1090

Open
ankursamarya opened this issue May 4, 2023 · 1 comment
Open

Var property's behaviour is not getting set #1090

ankursamarya opened this issue May 4, 2023 · 1 comment

Comments

@ankursamarya
Copy link

Hi All,

I have a class

class Car {
    var lights: Int = 5

    fun getAllLights(): Int {
        return lights + 2
    }
}

And have testing class

import io.mockk.every
import io.mockk.spyk
import org.junit.Assert
import org.junit.Before
import org.junit.Test

class CarTest {
    private lateinit var car: Car

    @Before
    fun setUp() {
        car = spyk(Car())
    }

    @Test
    fun `test lights`() {

        every { car.lights } returns 20

        val lights = car.getAllLights()

        Assert.assertEquals(20 + 2, lights)
    }
}

This test is failing with error

java.lang.AssertionError: expected:<22> but was:<7>
	at org.junit.Assert.fail(Assert.java:89)
	at org.junit.Assert.failNotEquals(Assert.java:835)
	at org.junit.Assert.assertEquals(Assert.java:120)
	at org.junit.Assert.assertEquals(Assert.java:146)
       ...

Mean lights is not getting mocked.
Please help in fixing this issue.
Thanks in advance.

@marik-rogenski
Copy link

To get your test passing, instead of using every { car.lights } returns 20, you could directly set car.lights to be 20 (car.lights = 20). You could accomplish the same in the setUp function with the following:

@Before
fun setUp() {
    car = spyk(Car()) {
        lights = 20
    }
}

To address the issue, I took a look into this a little bit. I found that if an explicit getter were added to lights, then the test would pass. Example:

class Car {
    var lights: Int = 5
        get() = field

    fun getAllLights(): Int {
        return lights + 2
    }
}

IntelliJ identifies this as a redundant getter, but having that getter changes the Bytecode for getAllLights(). Instead of using GETFIELD, it uses INVOKEVIRTUAL.

Generated Bytecode for getAllLights() when lights lacks an explicit getter:

  public final getAllLights()I
   L0
    LINENUMBER 5 L0
    ALOAD 0
    GETFIELD Car.lights : I
    ICONST_2
    IADD
    IRETURN

Generated Bytecode for getAllLights() when lights has an explicit getter:

  public final getAllLights()I
   L0
    LINENUMBER 6 L0
    ALOAD 0
    INVOKEVIRTUAL Car.getLights ()I
    ICONST_2
    IADD
    IRETURN
   L1

I believe every { car.lights } returns 20 does not work because the getter is being mocked, but since by default the getAllLights method directly accesses the field, the mocked getter is not used.

In terms of fixing it, I'm not really sure, but I wanted to post my findings in case it could help someone else.

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