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

igor.wojda

11/24/2021, 2:18 PM
These Kotlin helper methods (lie
mutableListOf
) to create collections are quite handy, but I find them a bit painfull for testing:
Copy code
class Bus {

    private val persons = mutableSetOf<Person>()
    
    fun addPerson(persons: Person) {
        persons.add(person)
    }
}
^ no easy way to test that person was added to the list. We can always create a factory or pass in constructor, but I wonder how do you deal with that? Is there anything better?
j

Joffrey

11/24/2021, 2:19 PM
no easy way to test that person was added to the list
How are those helpers different from any other kind of internal state in your class?
how do you deal with that?
Private state should be private. The class can be tested through its apparent behaviour via its public API. Everything private is an implementation detail that is irrelevant for testing. The classic question is "but how do you test the method
addPerson
then?", and the answer is you don't. You don't test methods, you test use cases of behaviour. So in this case I'd say your tests should consist of calls to
addPerson
+ calls to whatever other methods are impacted by this state change, and they should assert that the sequence of calls behaves as expected. Repeat for as many use cases as you want to support
12
r

Roukanken

11/24/2021, 2:40 PM
Think of it like this: I have a function
List<Int>.sum(): Int
which does the obvious but (even if it was possible) I don't go and check "did this function iterate the whole list?", I only check if the result is correct (on multiple example lists) If the function somehow sums up the list (correctly, every time) without iterating it then I don't care 🤷, only better for me, since it would be probably faster
e

ephemient

11/24/2021, 5:21 PM
I'm a fan of property testing in general. for example, with jetCheck you can write
Copy code
checkScenarios {
    val list = mutableListOf<Int>()
    var expectedSum = 0
    ImperativeCommand { env ->
        env.executeCommands(
            constant(ImperativeCommand { env ->
                val element = env.generateValue(integers(), null)
                list += element
                expectedSum += element
                assertEquals(expectedSum, list.sum())
            })
        )
    }
}
or simpler
Copy code
forEach(listsOf(integers()) { it.sum() == it.fold(0, Int::plus) }
and it generates a hundreds of test cases for you. this helps keep you focused on testing the intended behavior of the subject, not its implementation, and can catch edge cases you didn't know you had