直積使ってテストコードを書く
直積集合を作るライブラリを作りました。
GitHub - doilux/cartesian-product
これを使ってテストコードを書いてみます。 (注意:上記のライブラリのIFを変えたので、下記コードは参考です)
プロダクトコードはこんな感じ
public class DrivingResolver { public static boolean canDrive(Driver driver, Vehicle vehicle) { return (driver.equals(Driver.TAKA) && vehicle.equals(Vehicle.MOTOR_CYCLE)) || (driver.equals(Driver.JURI) && vehicle.equals(Vehicle.CAR)); } } public enum Driver { TAKA, HAJIME, JURI; } public enum Vehicle { MOTOR_CYCLE, CAR; }
↓のようなテストは書きたくないorz なぜなら、Enumの値が増えるたびにwhereブロックのパターンが増えるため。 スケールしないコードと言えます。
def "CanDrive"() { expect: DrivingResolver.canDrive(driver, vehicle) == result where: driver | vehicle || result Driver.TAKA | Vehicle.MOTOR_CYCLE || true Driver.TAKA | Vehicle.CAR || false Driver.HAJIME | Vehicle.MOTOR_CYCLE || false Driver.HAJIME | Vehicle.CAR || false Driver.JURI | Vehicle.MOTOR_CYCLE || false Driver.JURI | Vehicle.CAR || true }
で、こうしてみます。
def "CanDrive"() { setup: def allPattern = CartesianProductResolver.resolve( new HashSet<Object>() {{addAll(Driver.values())}}, new HashSet<Object>() {{addAll(Vehicle.values())}} ) def driverblePattern = [[Driver.TAKA, Vehicle.MOTOR_CYCLE], [Driver.JURI, Vehicle.CAR]] def notDriverblePattern = allPattern.stream().filter { !driverblePattern.contains(it) }.collect(Collectors.toList()) expect: driverblePattern.stream().filter { !DrivingResolver.canDrive(it.get(0), it.get(1)) }.collect(Collectors.toList()).size() == 0 notDriverblePattern.stream().filter { DrivingResolver.canDrive(it.get(0), it.get(1)) }.collect(Collectors.toList()).size() == 0 }
こうすれば、Enum増えてもテストコード量はそんなに増えないです。