简体   繁体   English

使用 quarkus:dev 运行时,Equalsverifier 失败

[英]Equalsverifier fails when run with quarkus:dev

When running equalsverfier in quarkus dev mode, equalsverfier tests fail.在 quarkus 开发模式下运行 equalsverfier 时,equalsverfier 测试失败。

I tried to test a class with equalsverifier.我尝试使用 equalsverifier 测试 class。 This works in my IDE.这适用于我的 IDE。 I tried to use it in quarkus dev mode (by running./mvnw quarkus:dev), but then it fails with the following exception:我尝试在 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$1(FieldModifier.java:79)
        at nl.jqno.equalsverifier.internal.reflection.FieldModifier.lambda$change$3(FieldModifier.java:113)
        at nl.jqno.equalsverifier.internal.util.Rethrow.lambda$rethrow$0(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

Here's the class under test:这是正在测试的 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);
    }
}

And the test:和测试:

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();
    }
}

What am I missing here?我在这里想念什么?

EqualsVerifier uses Objenesis to create instances of classes, and it keeps the same reference of the objenesis object around for performance reasons. EqualsVerifier 使用Objenesis创建类的实例,并且出于性能原因,它保持与对象 object 相同的引用。 It caches all the objects it has created before, so that makes things quicker when you want to create the same object over and over again, which EqualsVerifier tends to do.它缓存了它之前创建的所有对象,因此当您想要一遍又一遍地创建相同的 object 时,这会使事情变得更快,而 EqualsVerifier 往往会这样做。

However, EqualsVerifier keeps a static reference to objenesis, which means that it lives as long as the JVM does.但是,EqualsVerifier 保留了 static 对对象的引用,这意味着它与 JVM 一样长。 It turns out that the Quarkus test runner can re-run the same tests again and again, and it creates a new class loader each time.事实证明,Quarkus 测试运行程序可以一次又一次地重新运行相同的测试,并且每次都会创建一个新的 class 加载程序。 But part of the equality of java.lang.Class is that the classloader that created the class, must also be the same.但是java.lang.Class的部分相等性是创建 class 的类加载器也必须相同。 So it couldn't retrieve these objects from its cache anymore and returnd instances with classloaders that are now different from the other objects created in the test, and this caused the exceptions that you saw.因此,它无法再从其缓存中检索这些对象,并返回带有类加载器的实例,这些类加载器现在与测试中创建的其他对象不同,这导致了您看到的异常。

In version 3.8 of EqualsVerifier (created as a result of this StackOverflow post), this issue can be avoided by adding #withResetCaches() like this:在 EqualsVerifier 的 3.8 版中(由 StackOverflow 帖子创建),可以通过添加#withResetCaches()来避免此问题,如下所示:

EqualsVerifier.forClass(Dingetje.class)
    .withResetCaches()
    .withNonnullFields("text")
    .verify();

That fixes the problem.这解决了问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM