Hi, TL;DR I have data classes that contain nullab...
# getting-started
h
Hi, TL;DR I have data classes that contain nullables but no default values. can I add these default values retrospectively without touching the data class itself, like through an extention function or something in that direction? long version: I have a lib which includes generated data classes. Unfortunately this lib has a lot of nullables and for test purpose I need to instantiate those classes. That means that I have a constructor with currently 51 nulls. I f I fill one value in and then add some data to the generated class, the parameter order might shift and then it is a pain to find out in which of the 51 positions I need to add the value. It is a real paini, it is on the radar of the generator to add default values, but for now I cannot change this behaviour in the data class directly. Is there a way to add add these default values retrospectively without touching the data class itself, like through an extention function or something in that direction I can use in the meantime?? it might be hacky but I cannot imagine it being as hacky as 50/51 null values per test case 😓
s
you can create an extention function wich call the construtor. in your function give a default value for each parameter and in your unit test call the non null parameter with name.
h
@Sylvain Moindron thank you for your quick response that does sound like a hacky solution, but at least I have the adaption and the 51 nulls in just one place. I think I will do this for now, does anybody have an idea of a different, maybe a bit less verbose solution?
m
you can also not have class with 51 constructor parameters 🙂 but apart from that I think that the solution above is good
h
As I say I have a generated class so I cannot change that. This data class is generated from a graphql query. And for production code this works fine as the mapping is all done inside the library. But for testing my interaction with it and mocking certain responses I need to instantiate a class, and as there are no default values there is just one huge constructor unfortunately. As I said I did ask them to change this and so hopefully in future this will be not neccessary. BUT in the Meantime I have the problem that I have very very hard to read code. And as I am very new to kotlin I thought there is a way. So I will now do the way @Sylvain Moindron mentioned and hopefully they fix it soon. If there is a different way after all I would be very interested to hearing about it though 🙂
@Sylvain Moindron @Milan Hruban Can I create an overload contructor for the data class itself? so that the data class has 2 constructors in the end? Currently the only way I could find was to create a helper function which gives you a new object back. but would be cool to somehow extend the data class the way that you can use that function as an alternative constructor 🙂
m
you can create constructors only for the classes that you own. I think "helper" function is fine, since you are talking about tests. Maybe have a look at fake constructors https://blog.kotlin-academy.com/effective-java-in-kotlin-item-1-consider-static-factory-methods-instead-of-constructors-8d0d7b5814b2
h
@Milan Hruban sorry, maybe I was not clear enough. for me using the 52 nulls is theoretically fnie as it is a test. but I ran into this issue and I thought I try to find out what options there are in kotlin. so again - the helper funktion works (already implemented it) BUT then again maybe there is somethin kotlin-specific, so I can learn more kotlin-style with my ‘problems’ So the last hint is a real treat, thank you so much @Milan Hruban Unfortunately I seem not to be able to get this to work So I guess the generate classes are not really kotlin style so it seems very difficult to use them in a kotlin way. I have a structure like this in a file “Api.kt”:
Copy code
class TestSuperClass {
  data class SomeTestClass(val property1: String?, val property2: String?)
}
Then I try to create a function for tests in a file “Extentions.kt” looking like this:
Copy code
import de.europace.pm.edge.api.legacy.TestSuperClass.SomeTestClass

inline fun SomeTestClass(property1: String? = null): SomeTestClass = SomeTestClass(property1 = property1, property2 = null)
When I then try to call that funktion in my test though, it cannot be found and I get the compile errors
Copy code
No value passed for parameter 'property1'
No value passed for parameter 'property2'
When The data class is outside the
TestSuperClass
, it works as expected with the overloaded constructor. So is that a limitation or is there a tweak I have to add to my extention function for it to work? I could totally understand if that is not possible, as it seems odd to generate the data classes inside the other class, but I cannot change that yunfortunately as I am too happy for the other way it works with graphql to change it bcause I do not like the way to write tests 😅
m
try this
Copy code
inline fun SomeTestClass(property1: String? = null): TestSuperClass.SomeTestClass = TestSuperClass.SomeTestClass(property1 = property1, property2 = null)
t
alternatively, instead of instantiating your class, you could mock it.
Copy code
val myDataClass = mockk<DataClass>{
  every { property } returns "something"
} //for instance, with <http://mockk.io|mockk.io>
this way it is also clear which of the values are actually used in which specific use case
h
@thanksforallthefish ah interesting alternative, thank you, I use mockk already and I am very happy with it, so yes that is a good alternative indeed 🙂 I am kind of interested in the solution by @Milan Hruban though as I want to practice more n my Extension skills, coming from Java I am still learing the imense flexibility it gives you 🙂
m
If I fill one value in and then add some data to the generated class, the parameter order might shift and then it is a pain to find out in which of the 51 positions I need to add the value.
this is the exactly one of the problems that named arguments were meant solve