J'ai une question sur JUnit assertEquals
pour tester les double
valeurs. En lisant le document de l' API, je peux voir:
@Deprecated public static void assertEquals(double expected, double actual)
Obsolète. Utilisez
assertEquals(double expected, double actual, double delta)
plutôt.
(Remarque: dans les anciennes versions de documentation, le paramètre delta est appelé epsilon)
Que signifie le paramètre delta
(ou epsilon
)?
java
unit-testing
junit
Édipo Féderle
la source
la source
<=
pas être le cas<
.doubleIsDifferent
(pour comparer des valeurs doubles) et qu'il retourneMath.abs(d1 - d2) > delta
. Donc, si la différence entre d1 et d2 est supérieure à delta, cela signifie que les valeurs sont différentes et renverront true. Il renverra false si les valeurs sont considérées comme égales. Cette méthode est appelée directement dans assertEquals et si elle renvoie true, l'assertEquals appellerafailNotEquals
et le résultat du test sera un échec.De quelle version de JUnit s'agit-il? Je n'ai jamais vu que delta, pas epsilon - mais c'est un problème secondaire!
Depuis le javadoc JUnit :
C'est probablement exagéré, mais j'utilise généralement un très petit nombre, par exemple
private static final double DELTA = 1e-15; @Test public void testDelta(){ assertEquals(123.456, 123.456, DELTA); }
Si vous utilisez des assertions hamcrest , vous pouvez simplement utiliser le standard
equalTo()
avec deux doubles (il n'utilise pas de delta). Cependant, si vous voulez un delta, vous pouvez simplement utilisercloseTo()
(voir javadoc ), par exempleprivate static final double DELTA = 1e-15; @Test public void testDelta(){ assertThat(123.456, equalTo(123.456)); assertThat(123.456, closeTo(123.456, DELTA)); }
Pour info, la prochaine JUnit 5 rendra également le delta facultatif lors d'un appel
assertEquals()
avec deux doubles. La mise en œuvre (si vous êtes intéressé) est:private static boolean doublesAreEqual(double value1, double value2) { return Double.doubleToLongBits(value1) == Double.doubleToLongBits(value2); }
la source
Les calculs en virgule flottante ne sont pas exacts - il y a souvent des erreurs d'arrondi et des erreurs dues à la représentation. (Par exemple, 0,1 ne peut pas être représenté exactement en virgule flottante binaire.)
Pour cette raison, comparer directement deux valeurs à virgule flottante pour l'égalité n'est généralement pas une bonne idée, car elles peuvent être légèrement différentes, en fonction de la façon dont elles ont été calculées.
Le "delta", comme on l'appelle dans les javadocs JUnit , décrit la quantité de différence que vous pouvez tolérer dans les valeurs pour qu'elles soient toujours considérées comme égales. La taille de cette valeur dépend entièrement des valeurs que vous comparez. Lorsque je compare des doubles, j'utilise généralement la valeur attendue divisée par 10 ^ 6.
la source
Le fait est que deux doubles peuvent ne pas être exactement égaux en raison de problèmes de précision inhérents aux nombres à virgule flottante. Avec cette valeur delta, vous pouvez contrôler l'évaluation de l'égalité basée sur un facteur d'erreur.
De plus, certaines valeurs à virgule flottante peuvent avoir des valeurs spéciales telles que NAN et -Infinity / + Infinity qui peuvent influencer les résultats.
Si vous avez vraiment l'intention de comparer que deux doubles sont exactement égaux, il est préférable de les comparer comme une longue représentation
Ou
Assert.assertEquals(0, Double.compareTo(expected, result));
Ce qui peut prendre en compte ces nuances.
Je n'ai pas approfondi la méthode Assert en question, mais je ne peux que supposer que la précédente était obsolète pour ce genre de problèmes et que la nouvelle les prend en compte.
la source
Epsilon est une différence entre
expected
et desactual
valeurs que vous pouvez accepter en pensant qu'elles sont égales. Vous pouvez définir.1
par exemple.la source
Notez que si vous ne faites pas de maths, il n'y a rien de mal à affirmer des valeurs en virgule flottante exactes. Par exemple:
public interface Foo { double getDefaultValue(); } public class FooImpl implements Foo { public double getDefaultValue() { return Double.MIN_VALUE; } }
Dans ce cas, vous voulez vous assurer que c'est vraiment
MIN_VALUE
, pas zéro ou-MIN_VALUE
ouMIN_NORMAL
ou une autre très petite valeur. Tu peux diredouble defaultValue = new FooImpl().getDefaultValue(); assertEquals(Double.MIN_VALUE, defaultValue);
mais cela vous donnera un avertissement de dépréciation. Pour éviter cela, vous pouvez appeler à la
assertEquals(Object, Object)
place:// really you just need one cast because of autoboxing, but let's be clear assertEquals((Object)Double.MIN_VALUE, (Object)defaultValue);
Et, si vous voulez vraiment avoir l'air intelligent:
Ou vous pouvez simplement utiliser des assertions de style Hamcrest couramment:
// equivalent to assertEquals((Object)Double.MIN_VALUE, (Object)defaultValue); assertThat(defaultValue, is(Double.MIN_VALUE));
Si la valeur que vous vérifiez ne venez de faire un peu de maths, bien que, utilisez le epsilon.
la source
Assert.assertTrue(Math.abs(actual-expected) == 0)
la source