Support more than 3 arguments when `extracting`
Currently, extracting only supports 3 arguments max:
assertThat(users)
.extracting(User::name, User::email, User::password)
.containsExactly(
Triple("one", "[email protected]", "onePassword"),
Triple("two", "[email protected]", "twoPassword"),
)
It seems like this is due to Kotlin's generic tuples only supporting 3 arguments via Triple.
Was wondering if it is possible to support more than 3 arguments for extracting and we can implement our own Tuple type (maybe we can use Any type since this will usually only be used for expectations?) to support n number of arguments.
Rough idea of resulting usage:
assertThat(users)
.extracting(User::name, User::email, User::password, User::address)
.containsExactly(
Tuple("one", "[email protected]", "onePassword", "oneAddress"),
Tuple("two", "[email protected]", "twoPassword", "twoAddress"),
)
It seems like this is due to Kotlin's generic tuples only supporting 3 arguments via Triple.
That is correct, didn't want to have to design our own tuple types if could be avoided. It wasn't clear from your wording if this is a problem you ran into our purely hypothetical. If real, do you have any thoughts on how many we should go up to? Due to kotlin's type system we'd need a type per arity, unless we are ok with giving up type-safety here.
Also if we are ok with giving up type-safety, we could return List<Any?>. I don't love it but it might work well-enough for these uses-cases:
assertThat(users)
.extracting(User::name, User::email, User::password, User::address)
.containsExactly(
listOf("one", "[email protected]", "onePassword", "oneAddress"),
listOf("two", "[email protected]", "twoPassword", "twoAddress"),
)
Another aside, if you are extracting a lot of fields, it might be better to create your own mapping class.
data class UserFields(val name: String, val email: String, val password: String, val address: String)
assertThat(users)
.extracting { user -> UserFields(user.name, user.email, user.password, user.address) }
.containsExactly(
UserFields("one", "[email protected]", "onePassword", "oneAddress"),
UserFields("two", "[email protected]", "twoPassword", "twoAddress"),
)
you error message will be more readable because it will include the field names and not just the values.
The use case in real life was actually to extract more than 3 fields via lambdas (I was thinking it is easier to illustrate with properties). The data in question is kind of like a json map structure where the keys could change at runtime.
I think the List<Any?> would solve the issue. I prefer to have a more dynamic solution for test cases as it might be rather tedious to have a new data class for each slightly different test case (they might extract different fields each time). That said, I do understand that type-safety might be the goal of the project.
On the other hand, data class solution would work if the test cases all line up nicely with the same set of fields.