I'm kind of proud of this test: ``` @Parameteri...
# codereview
d
I'm kind of proud of this test:
Copy code
@ParameterizedTest(name = "{0} radians is {1}")
    @CsvSource(
        "NORTH, 3π/2",
        "EAST, 0",
        "SOUTH, π/2",
        "WEST, π",
    )
    fun radians(direction: Direction, @ConvertWith(NPiOverMConverter::class) expected: Double) {
        assertEquals(expected, direction.radians)
    }

    companion object {
        private val pattern = Regex("""(\d+)?(π)?(?:/(\d+))?""")

        class NPiOverMConverter : ArgumentConverter {
            override fun convert(value: Any?, context: ParameterContext): Any {
                if (value !is String) {
                    throw IllegalArgumentException("Invalid value: $value")
                }
                val (n, pi, m) = requireNotNull(pattern.matchEntire(value)) {
                    "Invalid value: $value"
                }.destructured

                val nValue = n.toDoubleOrNull() ?: 1.0
                val mValue = m.toDoubleOrNull() ?: 1.0
                val piValue = if (pi == "π") Math.PI else 1.0
                return nValue * piValue / mValue
            }
        }
    }
very nice 2
l
Can't you make
ArgumentConverter
into a generic type so that the
convert
function takes and return a specific type?
d
ArgumentConverter is a JUnit API, so I can’t change its signature.
c
I'm not sure I understand, where's the test, what's the system-under-test? The
radians
function only asserts its inputs. Unless the system-under-test is the argument converter? But that's strange, it looks like machinery, not actual code.
d
The system under test is the
Direction
enum. I'm validating the radians value is calculated properly.
The actual test class has a lot more tests of the
Direction
class.
c
I don't like how much code there is in the argument converter. If there was an error there, the test would be useless, and there isn't really a good way to check that it is correct (maybe through mutation testing?). Here's an alternative variant using Prepared and #parameterize:
Copy code
parameterize {
    val data by parameterOf(
        Direction.NORTH to (3 * PI / 2),
        Direction.EAST to (0.0),
        Direction.SOUTH to (PI / 2),
        Direction.WEST to (PI),
    )
    val (direction, expected) = data

    test("$direction radians is $expected") {
        assertEquals(expected, direction.radians)
    }
}
As you can see, there is no processing whatsoever. The test just tests the data. But honestly, even this seems overkill. If I were in your situation, I may not even use any parametrization at all and just write four tests, they're one-liners anyway. Also, I'm suspicious of using
assertEquals
on
Double
, especially when
PI
is involved.
1