Difference between InDelta and InEpsilon
Asked Answered
B

1

7

From documentation:

https://godoc.org/github.com/stretchr/testify/assert#InDelta

InDelta asserts that the two numerals are within delta of each other

https://godoc.org/github.com/stretchr/testify/assert#InEpsilon

InEpsilon asserts that expected and actual have a relative error less than epsilon

And their code seems to be identical in purpose:

func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {

    af, aok := toFloat(expected)
    bf, bok := toFloat(actual)

    if !aok || !bok {
        return Fail(t, fmt.Sprintf("Parameters must be numerical"), msgAndArgs...)
    }

    if math.IsNaN(af) {
        return Fail(t, fmt.Sprintf("Expected must not be NaN"), msgAndArgs...)
    }

    if math.IsNaN(bf) {
        return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...)
    }

    dt := af - bf
    if dt < -delta || dt > delta {
        return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
    }

    return true
}

func calcRelativeError(expected, actual interface{}) (float64, error) {
    af, aok := toFloat(expected)
    if !aok {
        return 0, fmt.Errorf("expected value %q cannot be converted to float", expected)
    }
    if af == 0 {
        return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error")
    }
    bf, bok := toFloat(actual)
    if !bok {
        return 0, fmt.Errorf("actual value %q cannot be converted to float", actual)
    }

    return math.Abs(af-bf) / math.Abs(af), nil
}

// InEpsilon asserts that expected and actual have a relative error less than epsilon
//
// Returns whether the assertion was successful (true) or not (false).
func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
    actualEpsilon, err := calcRelativeError(expected, actual)
    if err != nil {
        return Fail(t, err.Error(), msgAndArgs...)
    }
    if actualEpsilon > epsilon {
        return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+
            "        < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...)
    }

    return true
}

What is the difference? what are the use cases where one would be used over the other and vice versa?

Biisk answered 25/7, 2017 at 17:46 Comment(0)
D
22

They are related but not identical.

InDelta receives an absolute value and checks that the difference is less than that value.

InEpsilon receives a % of difference that would be acceptable.

The behaviour of InDelta is quite straightforward:

InDelta(t, 100, 101, 2) // that's OK
InDelta(t, 100, 103, 2) // fail!

But sometimes, you just care that the actual value is not too far away from the expected value.

Depending on how small or large the expected value is "not too far away" might get tricky with InDelta.

It might be a problem to use the same delta value for any number:

InDelta(t, 100, 101, 2) // ok, 101 is "not too far away" from 100
InDelta(t,   1,   2, 2) // hm, 2 sounds "too far away" from 1...

If you use InEpsilon, you can always use the same %:

InEpsilon(t, 100, 101, 0.02) // ok, up to 102 would be acceptable
InEpsilon(t,   1,   2, 0.02) // will not pass.. this time up to 1.02 would be acceptable

In summary, the use case for InEpsilon is to discard small differences (and making "small" relative to the actual values compared).

Detribalize answered 25/7, 2017 at 18:1 Comment(1)
Thanks! great answer.. should be in Go documentation :)Biisk

© 2022 - 2024 — McMap. All rights reserved.