I am solving problems on <https://projecteuler.net...
# announcements
a
I am solving problems on https://projecteuler.net and want to employ TDD. There are often utility methods closely coupled to each problem I am solving, so much so that it might not be appropriate to make a utility class to include top-level functions. How do you recommend me best unit testing these top-level functions? ... is it a bad practice to include the specific top-level functions in the same class as my problem?
right now all problems are separated in classes implementing
Copy code
interface Problem<T> {
    fun solve() : T
}
d
I would separate them, I've done project euler in the past
Usually I have like a PrimeUtil class or something
And one for generating permutations / combinations
Stuff like that
For something like prime numbers, TDD works fine, because the tests are trivial
w
Isn't possible to make use of Kotlin Extensions instead of the
Utils
classes? So you can write the test and code with TDD for each Extension in isolation and then move to the other part itself?
a
@Davio separate even for very specific things like
Copy code
fun productSumFactors(max: Int) = sequence {
    val size = log2(max.toDouble()).toInt() + 1
    val array = List(size) { 1 }.toIntArray()

    while (true) {
        var indexOn = array.size - 1
        array[indexOn]++
        var reduced: Int

        while (array.reduce { acc, i -> acc * i }.also { reduced = it } > max) {
            indexOn--
            if (indexOn < 0) return@sequence
            val nextIndex = array[indexOn]++
            array[indexOn + 1] = nextIndex
        }

        val sum = array.sum()
        val k = size + (reduced - sum)

        yield(FactorResult(k, reduced))
    }
}
?
d
It's only possible if you can generalize some things, and I mean a Utils class as just a name for the file holding top level extension functions, so you can do
2.isPrime()
a
@wbertan I don't see how extension functions would help... yes they make everything cleaner, but how would they help with isolation?
@Davio in sake of efficiency some of my functions are not very generalized... I already have a util class which has extension functions like
2.isPrime()
... however, in this scenario I would only be using this functions for this one problem
k
Just make a separate test file for the util file? Am I missing something?
d
Only works if you can generalize; in this case you could generalize summing a sequence not counting duplicates, like an extension function
Sequence<T>.distinctSum()
w
What I mean in isolation was the case you said the utility was too coupled to the solution, so using the Extensions you could decouple and even reuse it without worrying in test that behaviour in your problem (it was already tested, you are using it).
Besides often I make an extension private in my class (when it is relevant only for that class), and as far as I understand, that being private you will not test it directly, you test your public interfaces, so you test your
solve
function regardless of what is inside, which makes easy for later refactor the code, move code around, etc, and your test keeps checking if you are not breaking things up.
a
@karelpeeters that could make sense... however what I am asking is does it make sense to include a function that pertains to one problem in a utility class at all? I mean it would make unit testing much easier @wbertan the issue I see with only testing
solve()
is what if I have three separate, specific, coupled functions used in
solve()
I might want to test each function individually to better pinpoint what is not working when I am developing it
k
Sure, if it's general enough and doesn't need to "know" about the challenge.
w
Well, that is implementation details isn't, if the functions are public you can test each one in isolation, if they are private do you care? Since the behaviour of your external function gives to you the expected behaviour. Is like your test doesn't "see" those private functions, it cares and knows about the
solve
giving
6
returns
30
, etc. You can achieve today that value using the
while
as you are doing, and tomorrow refactor that to use an external library, or use a tail recursive function, your test will be the same (the behaviour didn't change).