https://kotlinlang.org logo
#getting-started
Title
# getting-started
g

Gasan

11/10/2023, 4:15 PM
Hi all, is there an easy way to create zero values in kotlin? The value of the type whre each field is initialized with some allowed zero value. Empty string, null reference if nullable, 0, false, etc.
j

Joffrey

11/10/2023, 4:15 PM
What do you mean by zero values?
j

Jacob

11/10/2023, 4:15 PM
val x = 0
g

Gasan

11/10/2023, 4:17 PM
@Joffrey empty string, 0 for int, false for boolean, null for nullable reference.
j

Joffrey

11/10/2023, 4:18 PM
I guess this list isn't helpful to you, is it?
""
,
0
,
false
,
null
g

Gasan

11/10/2023, 4:19 PM
for exaple, I have a data class. I want to test it. I don’t care abot the field values, but I have to provide them all in the construtctor
would be nice to just call
newMyType()
and have the value all initialized
j

Joffrey

11/10/2023, 4:20 PM
If you really want to just call the constructor this way, you can of course provide default values for constructor parameters. But most likely the test shouldn't be agnostic to the values passed to the constructor
👍 1
plus1 1
Could you please show an example? Like how your test looks like and why it doesn't care about the value passed to the constructor?
g

Gasan

11/10/2023, 4:22 PM
@Joffrey yes, that’s true, but for some values it does not care. Indeed default values is the choice. But there are already default values. Can kotlin just use those?
j

Joffrey

11/10/2023, 4:22 PM
If you already defined default values, then you can call the constructor without providing the value for those arguments
g

Gasan

11/10/2023, 4:23 PM
say, I have a type with 10 fields, each of which are also data types and so on. I only interested in 1 field in 1 field, I don’t care about others
@Joffrey but I need to provide default values manually. I want to not do that, so that int is initialized to 0, string to empty string or null and so on. Like when you have a default constructor.
rith now the only solution is to use mocks everywhere
because they allow you to just create mock(myType) and you have a value of that type
but then my test is just mocks, mocks, mocks everywhere. I would rather use the real thing
j

Jacob

11/10/2023, 4:28 PM
So you want the behavior from java classes where uninitialized properties are all set to zero for primitives and null for objects. I don’t think you can get that with kotlin properties defined in the primaryConstructor. You’ll have to manually define the defaults in the primaryConstructor
g

Gasan

11/10/2023, 4:29 PM
ok, got it, I looked at no-arg compiler plugin, but it appears that those constructors are only callable from reflection
thanks. I guess I have to mock everything 😄
but ok, explicit default arguments is not much work. I will add those. Another thing, is it possible to call a
copy()
method for individual fields from Java?
right now only the
copy()
for all fields is available
j

José González D'Amico

11/10/2023, 4:37 PM
maybe it would be better to start another thread with that 2nd question?
g

Gasan

11/10/2023, 4:38 PM
right, sorry, thanks
j

José González D'Amico

11/10/2023, 4:38 PM
no problem, just a suggestion to increase the chances of visibility for it
w

Wout Werkman

11/10/2023, 4:38 PM
Well, it's a tradeoff of statically compiled languages. Mocked data breaks an assumption of the type system. Instead of mocking or making your values nullable for the sake of testing, a common approach is the Object Mother pattern (or derived patterns). Useful post you might want to read: https://anderssv.medium.com/easy-and-maintainable-test-data-the-kotlin-way-9ecbbf53d822 Either mocking or changing your source code to allow illegal state in favor of testing is not recommended and is likely to haunt you in the future
g

Gasan

11/10/2023, 4:45 PM
@Wout Werkman I am not asking to allow illegal state. The zero value is a fully valid state, with all fields zero-ed to valid “zero” value of their type.
but indeed, there may be some invariants, like field lenght or value that are checked that is hard to reverse-engineer
thank you
w

Wout Werkman

11/10/2023, 4:48 PM
Ah that's great! In that case I'm quite confident that you can get away without mocking and instead using code and
.copy
. But based on your second question you already figured that out yourself 🙂.
c

Charles Flynn

11/11/2023, 9:12 AM
A pattern I like to follow for initialising data where a test only cares about some of it is to design a function which takes defaulted parameters (with random data not 0'd) and provides them to the constructor so a test can implement what it needs.
Copy code
fun aPerson(
  name: String = randomString(),
  age: Int = randomInt(1, 100)
  eyeColour: EyeColour = randomEnumValue()
) = Person(name, age, eyeColour)
Then in a test that say only cares about being provided an adult but not their name or eye colour you'd just go
val adult = aPerson(age = 18)
. It's a useful technique because in production code it might not be appropriate to set defaults but in tests you do end up in this scenario of only caring about certain fields. It also helps to self document your tests in that regard. There's a library which I've not used because it seems a bit overkill to me but you might be interested in: https://serpro69.github.io/kotlin-faker/ Do not use mocks for this type of thing.
a

Adam S

11/11/2023, 9:14 AM
In a similar vein, there's property based testing https://kotest.io/docs/proptest/property-based-testing.html You can generate random data for your data class. It's really powerful because one test could test all possible variations.
2 Views