doilux’s tech blog

ITに関する備忘録。 DDP : http://doiluxng.hatenablog.com/entry/2018/01/01/195409

直積使ってテストコードを書く

直積集合を作るライブラリを作りました。

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増えてもテストコード量はそんなに増えないです。