2

I was writing an integration test where I am using the same instance of SparkConsumer for all the tests using @BeforeAll.

However, between every test, I want to pass different instances of the mocks with @BeforeEach that are injected in the constructor of SparkConsumer without making the internals of SparkConsumer mutable.

The simpler solution I could think of is to pass a proxy instance to the constructor which could watch the current mock instance.

I can use the Delegation feature of Kotlin, but I have concluded that it's only made for delegating to an instance known at initialization.

I made three attempts during my research:

  • Option A - by Anonymous instance, it works but it's not elegant

        SUT = SparkConsumer(PORT, object : IEventsService {
            override fun create(eventRequest: Event.Request)
                = eventsServiceMock.create(eventRequest)
        })
    
  • Option B - by a reference to the lateinit var: It evaluates immediately, and fails

        SUT = SparkConsumer(PORT, object : IEventsService by eventsServiceMock {})
    
  • Option C - by a Delegate property referencing the lateinit var: It evaluates the property immediately, and fails

    private val eventsServiceMockByLazy: IEventsService by object {
        operator fun getValue(thisRef: Any?, property: KProperty<*>): IEventsService = eventsServiceMock
    }
        SUT = SparkConsumer(PORT, object : IEventsService by eventsServiceMockByLazy {})
    

Here is some of the code:

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class SparkConsumerIntegrationTest {
    val PORT = 28411

    private lateinit var SUT: SparkConsumer
    private lateinit var eventsServiceMock: IEventsService
    private val eventsServiceMockByLazy: IEventsService by object { // For Option C only
        operator fun getValue(thisRef: Any?, property: KProperty<*>): IEventsService = eventsServiceMock
    }

    @BeforeAll
    fun beforeAll() {
        // Option A
        SUT = SparkConsumer(PORT, object : IEventsService {
            override fun create(eventRequest: Event.Request)
                = eventsServiceMock.create(eventRequest)
        })
        // Option B
        SUT = SparkConsumer(PORT, object : IEventsService by eventsServiceMock {})
        // Option C
        SUT = SparkConsumer(PORT, object : IEventsService by eventsServiceMockByLazy {})
    }

    @AfterAll
    fun afterAll() {
        SUT.kill()
    }

    @BeforeEach
    fun setUp() {
        eventsServiceMock = mock { }
    }

    @Test
    fun `should events-create pass`() {
        // S
        val requestObj = Event.Request("Some device", "Some statement")
        eventsServiceMock.stub {
            on {
                create(Event.Request("Some device", "Some statement"))

            }.doReturn(Event.Data("0123", "Some device", "Some statement"))
        }

        // ...
    }

    // ...
}

Is there a nice way to use the Class Delegation feature on an instance by reference / by function result in Kotlin?

i.e. Something like:

SparkConsumer(PORT, object : IEventsService by this::eventsServiceMock {})
Hay
  • 2,246
  • 20
  • 30
  • related: https://stackoverflow.com/q/48054110/3755692 – msrd0 Mar 18 '18 at 13:57
  • @msrd0 Oh wow it's exactly the same question; I didn't look hard enough I guess. It made me wonder if I should mark my question as a duplicate, but apparently [it shouldn't be done if it is unanswered](https://meta.stackoverflow.com/a/278361/4506528) – Hay Mar 18 '18 at 17:17
  • Yep you can't mark it as a duplicate - so let's hope that two questions get more attention than just one – msrd0 Mar 18 '18 at 17:21
  • Possible duplicate of [How can I delegate an implementation to a mutable property in Kotlin?](https://stackoverflow.com/questions/48054110/how-can-i-delegate-an-implementation-to-a-mutable-property-in-kotlin) – Raphael Nov 06 '18 at 13:03

0 Answers0