ably-java
ably-java copied to clipboard
Public Final Properties Make It Hard To Test
I'm trying to write a test to ensure that my code is using the Ably SDK correctly however the public final channels property is final and there is no accessor method. This makes mocking the channels object impossible.
Example:
fun handle(message: String) {
// Extract Key Fields From Message (name, userId) used to forward message to correct channel
// Note: Not extracting "payload" from json which changes for different values of $.name
val json = Configuration.defaultConfiguration().jsonProvider().parse(message)
val messageType = JsonPath.read<String>(json, "$.name")
val userId = JsonPath.read<Int>(json, "$.userId")
// Use SDK to publish to channel using the event name
client.channels.get(userId.toString())
.publish(messageType, message)
}
internal class AblyHandlerTest {
val mChannels = mock<AblyBase.Channels>()
val client = mock<AblyRest>()
val handler = AblyHandler(client)
@BeforeEach
fun before() {
// Does not exist - now impossible to write the test below
whenever(client.getChannels()).thenReturn(mChannels)
}
@Test
fun `it uses the name and user id to correctly route the message`() {
val rawMessage = """
{
"name": "UserUpdatedEvent",
"userId": 42,
"payload": { "nested": "data" }
}
""".trimIndent()
handler.handle(rawMessage)
verify(mChannels).get("42")
}
}
I'm 100% TDD and so this break in encapsulation feels a bit jarring, any chance of getting the accessor methods added?
Thanks!
Hello @benwaine - thanks for submitting this request and apologies for not responding sooner. This is something that we would like to improve soon as you're not the first person to mention it.
Yes, we're facing the same issues. Everything nicely tested, expect the Ably part... Would make a nice (and straight forward?) addition to the project.
For visibility: this issue has been reported again and we've found that the following workaround using Spring can be used in this instance to allow reflection on AblyRest.channels. Obviously the real solution here is to refactor the library itself but this should suffice as a hacky workaround for the time being.
AblyBase.class.getDeclaredField("channels").setAccessible(true);
ReflectionTestUtils.setField(ablyRest, "channels", mockChannels);