当 运行 和 quarkus:dev 时,Equalsverifier 失败
Equalsverifier fails when run with quarkus:dev
当 运行 在 quarkus 开发模式下使用 equalsverfier 时,equalsverfier 测试失败。
我试图用 equalsverifier 测试 class。这适用于我的 IDE。
我尝试在 quarkus 开发模式下使用它(通过 运行 ./mvnw quarkus:dev),但随后失败并出现以下异常:
ERROR [io.qua.test] (Test runner thread) Test DingetjeTest#implementsEquals() failed
: java.lang.AssertionError: EqualsVerifier found a problem in class a.Dingetje.
-> Can not set final java.lang.String field a.Dingetje.text to a.Dingetje
For more information, go to: http://www.jqno.nl/equalsverifier/errormessages
at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.verify(SingleTypeEqualsVerifierApi.java:308)
at a.DingetjeTest.implementsEquals(DingetjeTest.java:11)
Caused by: java.lang.IllegalArgumentException: Can not set final java.lang.String field a.Dingetje.text to a.Dingetje
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at java.base/jdk.internal.reflect.UnsafeQualifiedObjectFieldAccessorImpl.get(UnsafeQualifiedObjectFieldAccessorImpl.java:38)
at java.base/java.lang.reflect.Field.get(Field.java:418)
at nl.jqno.equalsverifier.internal.reflection.FieldModifier.lambda$copyTo(FieldModifier.java:79)
at nl.jqno.equalsverifier.internal.reflection.FieldModifier.lambda$change(FieldModifier.java:113)
at nl.jqno.equalsverifier.internal.util.Rethrow.lambda$rethrow[=12=](Rethrow.java:47)
at nl.jqno.equalsverifier.internal.util.Rethrow.rethrow(Rethrow.java:30)
at nl.jqno.equalsverifier.internal.util.Rethrow.rethrow(Rethrow.java:45)
at nl.jqno.equalsverifier.internal.util.Rethrow.rethrow(Rethrow.java:55)
at nl.jqno.equalsverifier.internal.reflection.FieldModifier.change(FieldModifier.java:113)
at nl.jqno.equalsverifier.internal.reflection.FieldModifier.copyTo(FieldModifier.java:79)
at nl.jqno.equalsverifier.internal.reflection.InPlaceObjectAccessor.copyInto(InPlaceObjectAccessor.java:43)
at nl.jqno.equalsverifier.internal.reflection.InPlaceObjectAccessor.copy(InPlaceObjectAccessor.java:24)
at nl.jqno.equalsverifier.internal.checkers.ExamplesChecker.checkSingle(ExamplesChecker.java:84)
at nl.jqno.equalsverifier.internal.checkers.ExamplesChecker.check(ExamplesChecker.java:47)
at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.verifyWithExamples(SingleTypeEqualsVerifierApi.java:413)
at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.performVerification(SingleTypeEqualsVerifierApi.java:369)
at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.verify(SingleTypeEqualsVerifierApi.java:304)
... 1 more
这是正在测试的 class:
package a;
import java.util.Objects;
public class Dingetje {
private final String text;
public Dingetje(String text) {
this.text = text;
}
@Override
public final boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Dingetje)) {
return false;
}
Dingetje other = (Dingetje) o;
return text.equals(other.text);
}
@Override
public final int hashCode() {
return Objects.hash(text);
}
}
测试:
package a;
import nl.jqno.equalsverifier.EqualsVerifier;
import org.junit.jupiter.api.Test;
class DingetjeTest {
@Test
void implementsEquals() {
EqualsVerifier.forClass(Dingetje.class)
.withNonnullFields("text")
.verify();
}
}
我在这里错过了什么?
EqualsVerifier 使用 Objenesis 来创建 classes 的实例,并且出于性能原因,它保留了对象对象的相同引用。它缓存它之前创建的所有对象,因此当你想一遍又一遍地创建相同的对象时,这会使事情变得更快,而 EqualsVerifier 往往会这样做。
但是,EqualsVerifier 保留了对 objenesis 的静态引用,这意味着它与 JVM 一样存在。事实证明,Quarkus 测试 运行ner 可以一次又一次地重新 运行 相同的测试,并且每次都会创建一个新的 class 加载程序。但是 java.lang.Class
的部分相等性是创建 class 的 classloader 也必须相同。因此,它无法再从其缓存中检索这些对象,并返回带有 classloader 的实例,这些实例现在与测试中创建的其他对象不同,这导致了您看到的异常。
在 EqualsVerifier 的 3.8 版中(由于这个 Whosebug post 而创建),可以通过添加 #withResetCaches()
来避免这个问题,如下所示:
EqualsVerifier.forClass(Dingetje.class)
.withResetCaches()
.withNonnullFields("text")
.verify();
这解决了问题。
当 运行 在 quarkus 开发模式下使用 equalsverfier 时,equalsverfier 测试失败。
我试图用 equalsverifier 测试 class。这适用于我的 IDE。 我尝试在 quarkus 开发模式下使用它(通过 运行 ./mvnw quarkus:dev),但随后失败并出现以下异常:
ERROR [io.qua.test] (Test runner thread) Test DingetjeTest#implementsEquals() failed
: java.lang.AssertionError: EqualsVerifier found a problem in class a.Dingetje.
-> Can not set final java.lang.String field a.Dingetje.text to a.Dingetje
For more information, go to: http://www.jqno.nl/equalsverifier/errormessages
at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.verify(SingleTypeEqualsVerifierApi.java:308)
at a.DingetjeTest.implementsEquals(DingetjeTest.java:11)
Caused by: java.lang.IllegalArgumentException: Can not set final java.lang.String field a.Dingetje.text to a.Dingetje
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at java.base/jdk.internal.reflect.UnsafeQualifiedObjectFieldAccessorImpl.get(UnsafeQualifiedObjectFieldAccessorImpl.java:38)
at java.base/java.lang.reflect.Field.get(Field.java:418)
at nl.jqno.equalsverifier.internal.reflection.FieldModifier.lambda$copyTo(FieldModifier.java:79)
at nl.jqno.equalsverifier.internal.reflection.FieldModifier.lambda$change(FieldModifier.java:113)
at nl.jqno.equalsverifier.internal.util.Rethrow.lambda$rethrow[=12=](Rethrow.java:47)
at nl.jqno.equalsverifier.internal.util.Rethrow.rethrow(Rethrow.java:30)
at nl.jqno.equalsverifier.internal.util.Rethrow.rethrow(Rethrow.java:45)
at nl.jqno.equalsverifier.internal.util.Rethrow.rethrow(Rethrow.java:55)
at nl.jqno.equalsverifier.internal.reflection.FieldModifier.change(FieldModifier.java:113)
at nl.jqno.equalsverifier.internal.reflection.FieldModifier.copyTo(FieldModifier.java:79)
at nl.jqno.equalsverifier.internal.reflection.InPlaceObjectAccessor.copyInto(InPlaceObjectAccessor.java:43)
at nl.jqno.equalsverifier.internal.reflection.InPlaceObjectAccessor.copy(InPlaceObjectAccessor.java:24)
at nl.jqno.equalsverifier.internal.checkers.ExamplesChecker.checkSingle(ExamplesChecker.java:84)
at nl.jqno.equalsverifier.internal.checkers.ExamplesChecker.check(ExamplesChecker.java:47)
at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.verifyWithExamples(SingleTypeEqualsVerifierApi.java:413)
at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.performVerification(SingleTypeEqualsVerifierApi.java:369)
at nl.jqno.equalsverifier.api.SingleTypeEqualsVerifierApi.verify(SingleTypeEqualsVerifierApi.java:304)
... 1 more
这是正在测试的 class:
package a;
import java.util.Objects;
public class Dingetje {
private final String text;
public Dingetje(String text) {
this.text = text;
}
@Override
public final boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Dingetje)) {
return false;
}
Dingetje other = (Dingetje) o;
return text.equals(other.text);
}
@Override
public final int hashCode() {
return Objects.hash(text);
}
}
测试:
package a;
import nl.jqno.equalsverifier.EqualsVerifier;
import org.junit.jupiter.api.Test;
class DingetjeTest {
@Test
void implementsEquals() {
EqualsVerifier.forClass(Dingetje.class)
.withNonnullFields("text")
.verify();
}
}
我在这里错过了什么?
EqualsVerifier 使用 Objenesis 来创建 classes 的实例,并且出于性能原因,它保留了对象对象的相同引用。它缓存它之前创建的所有对象,因此当你想一遍又一遍地创建相同的对象时,这会使事情变得更快,而 EqualsVerifier 往往会这样做。
但是,EqualsVerifier 保留了对 objenesis 的静态引用,这意味着它与 JVM 一样存在。事实证明,Quarkus 测试 运行ner 可以一次又一次地重新 运行 相同的测试,并且每次都会创建一个新的 class 加载程序。但是 java.lang.Class
的部分相等性是创建 class 的 classloader 也必须相同。因此,它无法再从其缓存中检索这些对象,并返回带有 classloader 的实例,这些实例现在与测试中创建的其他对象不同,这导致了您看到的异常。
在 EqualsVerifier 的 3.8 版中(由于这个 Whosebug post 而创建),可以通过添加 #withResetCaches()
来避免这个问题,如下所示:
EqualsVerifier.forClass(Dingetje.class)
.withResetCaches()
.withNonnullFields("text")
.verify();
这解决了问题。