ได้รับ“ NoSuchMethodError: org.hamcrest.Matcher.describeMismatch” เมื่อเรียกใช้การทดสอบใน IntelliJ 10.5


233

ฉันใช้ JUnit-dep 4.10 และ Hamcrest 1.3.RC2

ฉันได้สร้าง matcher ที่กำหนดเองที่มีลักษณะดังนี้:

public static class MyMatcher extends TypeSafeMatcher<String> {
    @Override
    protected boolean matchesSafely(String s) {
        /* implementation */
    }

    @Override
    public void describeTo(Description description) {
        /* implementation */
    }

    @Override
    protected void describeMismatchSafely(String item, Description mismatchDescription) {

        /* implementation */
    }
}

มันทำงานได้อย่างสมบูรณ์แบบเมื่อทำงานจากบรรทัดคำสั่งโดยใช้ Ant แต่เมื่อเรียกใช้จาก IntelliJ มันล้มเหลวด้วย:

java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch(Ljava/lang/Object;Lorg/hamcrest/Description;)V
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:18)
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8)
    at com.netflix.build.MyTest.testmyStuff(MyTest.java:40)

ฉันเดาว่ามันใช้ผิด hamcrest.MatcherAssert ฉันจะค้นหา hamcrest.MatcherAssert ที่ใช้ (เช่นไฟล์ jar ใดที่ใช้สำหรับ hamcrest.MatcherAssert) ได้อย่างไร AFAICT เหยือก hamcrest เดียวใน classpath ของฉันคือ 1.3.RC2

IntelliJ IDEA ใช้สำเนา JUnit หรือ Hamcrest ของตัวเองหรือไม่

ฉันจะส่งออก runtime CLASSPATH ที่ IntelliJ ใช้ได้อย่างไร

คำตอบ:


272

ตรวจสอบให้แน่ใจว่าhamcrest jar นั้นสูงกว่าในคำสั่งการนำเข้ามากกว่าjar JUnitของคุณ

JUnitมาพร้อมกับorg.hamcrest.Matcherคลาสของตัวเองที่อาจถูกนำมาใช้แทน

คุณยังสามารถดาวน์โหลดและใช้junit-dep-4.10.jarแทนซึ่งเป็น JUnit โดยไม่มีคลาส hamcrest

mockito ยังมีคลาส hamcrest อยู่ด้วยเช่นกันดังนั้นคุณอาจต้องย้าย \ จัดลำดับใหม่เช่นกัน


1
OP บอกว่าพวกเขาใช้ขวด '-dep-' อยู่แล้ว แต่คุณเดาว่าการใช้คลาส Matcher จาก jar JUnit ฟังดูถูกต้อง ดังนั้นอาจเป็นไปได้ว่า IDE กำลังใช้ JUnit ของตนเอง
MatrixFrog

2
ฉันลบ junit.jar และ junit-4.8.jar ของ IntelliJ ออกแล้วติดตั้ง junit-dep-4.10.jar ลงใน lib / ไดเรกทอรีของ IntelliJ และปัญหายังคงเกิดขึ้น
Noel Yap

8
JUnit 4.11 เข้ากันได้กับ Hamcrest 1.3 และ JUnit 4.10 เข้ากันได้กับ Hamcrest 1.1 search.maven.org/remotecontent?filepath=junit/junit-dep/4.10/ …
Muthu

23
ตรวจสอบให้แน่ใจว่าคุณไม่ได้ใช้ mockito-all แต่แทนที่จะเป็น mockito-core ด้วยการยกเว้น hamcrest
Ulf Lindback

1
ในสำนักงานเวลา 19.33 น. ฉันกำลังทำงานเกี่ยวกับคุณสมบัติที่สำคัญที่ฉันต้องจัดส่งก่อนออกไปพักผ่อนในวันหยุดและเป็นวันศุกร์ฉันอยู่ในวันหยุดพักผ่อนในสัปดาห์หน้า !!!!!! ตอนนี้ฉันจะได้รับข้อผิดพลาดนี้ได้ไงเนี่ย !!!
Adelin

170

ปัญหานี้เกิดขึ้นเมื่อคุณมีmockito-allบนเส้นทางคลาสของคุณซึ่งเลิกใช้แล้ว

ถ้าเป็นไปได้มีเพียงMockito-core

Maven config สำหรับการผสม junit, mockito และ hamcrest:

<dependencies>
  <dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-core</artifactId>
    <version>1.3</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-library</artifactId>
    <version>1.3</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
  </dependency>
</dependencies>

2
ค่อนข้างเป็นเวอร์ชั่นใหม่ของ mockito รวมถึง hamcrest เช่นเดียวกันกับ powermock!
Tom Parkinson

3
นั่นควรเป็น mockito-core แทนที่จะเป็น mockito-all หรือไม่?
user944849

3
คุณสามารถรวมแกนหลักได้หากคุณต้องการเพียงแค่ก้าวเดียวเท่านั้นอย่างไรก็ตามข้างต้นควรใช้งานได้ในทุกกรณี ลำดับการขึ้นต่อกันคือบิตสำคัญ mvn 3 เริ่มต้นจากด้านบนตามลำดับความสำคัญ
Tom Parkinson

3
คุณไม่ควรรวม mockito-all ตั้งแต่ที่รวม hamcrest 1.1 แทนที่จะรวม mockito-core และยกเว้น hancrest จากมัน (ซึ่งคุณไม่สามารถทำได้จากทั้งหมด)
Ulf Lindback

1
ถ้าเป็นไปได้ให้ใส่ mockito-core ด้วย ". ตกลงดังนั้นทำไมคำตอบนี้ยังใช้ mockito-all
Stealth Rabbi

60

ปัญหาคือว่ามีการใช้คลาสที่hamcrest.Matcherไม่hamcrest.MatcherAssertถูกต้อง ที่ถูกดึงเข้ามาจากการพึ่งพา junit-4.8 หนึ่งในการอ้างอิงของฉันคือการระบุ

หากต้องการดูว่าการรวม (และรุ่น) ใดที่รวมอยู่ในแหล่งที่มาขณะทำการทดสอบให้เรียกใช้:

mvn dependency:tree -Dscope=test

5
ฉันมีปัญหาเดียวกัน ฉันใช้ JUnit-dep และ Hamcrest-core แต่ฉันมี Powermock ที่ระบุไว้ก่อนหน้านี้ใน pom ซึ่งส่งผลให้ JUnit ถูกรวมไว้ก่อน JUnit-dep และ Hamcrest
John B

9
mockito ยังรวมถึงบางคลาส Hamcrest มันจะดีกว่าที่จะใช้ mockito-core และไม่รวมการพึ่งพา hamcrest
Brambo

3
เพิ่งสะดุดกับปัญหาเดียวกันที่แน่นอน วิธีแก้ไขคือการเพิ่มรุ่น Junit เป็น 4.11 ซึ่งเข้ากันได้ (เช่น "มีคลาสจาก") ด้วย hamcrest 1.3
r3mbol

สำหรับผู้ที่ข้อเสนอแนะทั้งหมดใช้งานไม่ได้เช่นกัน (ลำดับการพึ่งพาการยกเว้นลบการแทนที่-allด้วย-coreฯลฯ ... ): ฉันต้องเปลี่ยน hamcrest กลับไปเป็นเวอร์ชัน 1.1 และตอนนี้ทุกอย่างทำงานได้อีกครั้ง
เฟลิกซ์ Hagspiel

1
สำหรับฉันมันใช้งานได้เมื่อฉันเปลี่ยนการนำเข้าเป็นimport static org.mockito.Matchers.anyString;จากimport static org.mockito.ArgumentMatchers.anyString;
Shrikant Prabhu

28

ต่อไปนี้ควรเป็นวันนี้ที่ถูกต้องที่สุด หมายเหตุ Junit 4.11 ขึ้นอยู่กับ hamcrest-core ดังนั้นคุณไม่จำเป็นต้องระบุเลยไม่สามารถใช้ mockito-all ได้ทั้งหมดเนื่องจากมันรวม (ไม่ขึ้นอยู่กับ) hamcrest 1.1

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>1.10.8</version>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

3
โปรดทราบว่าตอนนี้ JUnit 4.12 ขึ้นอยู่กับ hamcrest-core 1.3
JeeBee

การยกเว้นจากการช่วยให้ฉันไม่ได้mockito-all mockito-coreยังประกาศ Hamcrest ก่อน Mockito ในpom.xmlงาน
คิริลล์

13

สิ่งนี้ใช้ได้กับฉันหลังจากดิ้นรนเล็กน้อย

<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-all</artifactId>
    <version>1.3</version>
    <scope>test</scope>
 </dependency>

 <dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
 </dependency>

 <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
 </dependency>

เหมือนกับฉัน. การวางการอ้างอิงในลำดับนี้ช่วยให้ Maven แก้ไขค่าสกรรมกริยาได้อย่างถูกต้อง การยกเว้น hamcrest อย่างชัดเจนจาก mockito-core หรือ mockito-all อาจจะปลอดภัยกว่า แต่ในกรณีที่มีคนเรียงลำดับข้อมูลใหม่ใน pom ของคุณ
Mat

4

ลอง

expect(new ThrowableMessageMatcher(new StringContains(message)))

แทน

expectMessage(message)

คุณสามารถเขียนวิธีการที่กำหนดเองExpectedExceptionหรือยูทิลิตี้เพื่อสรุปโค้ด


4

ฉันรู้ว่านี่เป็นเธรดเก่า แต่สิ่งที่แก้ไขปัญหาสำหรับฉันคือการเพิ่มสิ่งต่อไปนี้ในไฟล์ build.gradle ของฉัน ตามที่ระบุไว้ข้างต้นมีปัญหาความเข้ากันได้กับmockito-all

อาจมีประโยชน์โพสต์ :

testCompile ('junit:junit:4.12') {
    exclude group: 'org.hamcrest'
}
testCompile ('org.mockito:mockito-core:1.10.19') {
    exclude group: 'org.hamcrest'
}
testCompile 'org.hamcrest:hamcrest-core:1.3'

1

แม้ว่าข้อเท็จจริงที่ว่านี้เป็นคำถามที่เก่ามากและอาจเป็นไปได้ว่าแนวความคิดก่อนหน้านี้หลายอย่างสามารถแก้ไขปัญหาได้มากมาย แต่ฉันยังต้องการแบ่งปันวิธีแก้ปัญหากับชุมชนที่แก้ไขปัญหาของฉัน

ฉันพบว่าปัญหาคือฟังก์ชันที่เรียกว่า "hasItem" ซึ่งฉันใช้เพื่อตรวจสอบว่า JSON-Array มีรายการเฉพาะหรือไม่ ในกรณีของฉันฉันตรวจสอบค่าชนิด Long

และสิ่งนี้นำไปสู่ปัญหา

อย่างใด Matchers มีปัญหากับค่าประเภท Long (ฉันไม่ได้ใช้ JUnit หรือ Rest-Assured มากดังนั้น idk แน่นอนว่าทำไม แต่ฉันเดาว่าข้อมูล JSON ที่ส่งคืนมีเพียงจำนวนเต็ม)

ดังนั้นสิ่งที่ฉันทำเพื่อแก้ไขปัญหาจริงคือต่อไปนี้ แทนที่จะใช้:

long ID = ...;

...
.then().assertThat()
  .body("myArray", hasItem(ID));

คุณเพียงแค่ส่งไปที่ Integer รหัสการทำงานจึงเป็นดังนี้:

long ID = ...;

...
.then().assertThat()
  .body("myArray", hasItem((int) ID));

นั่นอาจไม่ใช่วิธีที่ดีที่สุด แต่ฉันอยากจะพูดถึงว่าข้อยกเว้นสามารถถูกโยนได้เนื่องจากชนิดข้อมูลที่ไม่ถูกต้อง / ไม่รู้จัก


0

สิ่งที่ได้ผลสำหรับฉันคือไม่รวมกลุ่ม hamcrest จากการทดสอบ Junit Compile

นี่คือรหัสจาก build.gradle ของฉัน:

testCompile ('junit:junit:4.11') {
    exclude group: 'org.hamcrest'
}

หากคุณใช้ IntelliJ คุณอาจต้องเรียกใช้gradle cleanIdea idea clean buildเพื่อตรวจสอบการอ้างอิงอีกครั้ง


0

ฉันรู้ว่านั่นไม่ใช่คำตอบที่ดีที่สุด แต่ถ้าคุณไม่สามารถทำให้ classpath ทำงานได้นี่คือโซลูชันแผน B

ใน classpath ทดสอบของฉันฉันเพิ่มอินเทอร์เฟซต่อไปนี้ด้วยการใช้งานเริ่มต้นสำหรับเมธอดอธิบายการจับคู่

package org.hamcrest;

/**
 * PATCH because there's something wrong with the classpath. Hamcrest should be higher than Mockito so that the BaseMatcher
 * implements the describeMismatch method, but it doesn't work for me. 
 */
public interface Matcher<T> extends SelfDescribing {

    boolean matches(Object item);

    default void describeMismatch(Object item, Description mismatchDescription) {
        mismatchDescription.appendDescriptionOf(this).appendValue(item);
    }

    @Deprecated
    void _dont_implement_Matcher___instead_extend_BaseMatcher_();
}

0

ฉันมีโครงการ gradle และเมื่อส่วน build.gradle ของฉันมีลักษณะเช่นนี้:

dependencies {
    implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'

    testImplementation group: 'org.mockito', name: 'mockito-all', version: '1.10.19'
    testImplementation 'junit:junit:4.12'
//    testCompile group: 'org.mockito', name: 'mockito-core', version: '2.23.4'

    compileOnly 'org.projectlombok:lombok:1.18.4'
    apt 'org.projectlombok:lombok:1.18.4'
}

มันนำไปสู่ข้อยกเว้นนี้:

java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch(Ljava/lang/Object;Lorg/hamcrest/Description;)V

    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:18)
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8)

เพื่อแก้ไขปัญหานี้ฉันได้แทนที่ "mockito-all" ด้วย "mockito-core"

dependencies {
    implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.8.1'

//    testImplementation group: 'org.mockito', name: 'mockito-all', version: '1.10.19'
    testImplementation 'junit:junit:4.12'
    testCompile group: 'org.mockito', name: 'mockito-core', version: '2.23.4'

    compileOnly 'org.projectlombok:lombok:1.18.4'
    apt 'org.projectlombok:lombok:1.18.4'
}

คำอธิบายระหว่างmockito-allและmockito-coreสามารถดูได้ที่นี่: https://solidsoft.wordpress.com/2012/09/11/beyond-the-mockito-refcard-part-3-mockito-core-vs-mockito โครงการพักใน mavengradle-based-/

mockito-all.jar นอกจาก Mockito เองยังประกอบด้วย (จาก 1.9.5) สองการพึ่งพา: Hamcrest และ Objenesis (เราจะไม่บรรจุ ASM และ CGLIB สักครู่) เหตุผลก็คือมีทุกสิ่งที่จำเป็นภายใน JAR เดียวเพื่อใส่ไว้ใน classpath มันอาจดูแปลก แต่โปรดจำไว้ว่าการพัฒนา Mockito เริ่มขึ้นในเวลาที่ Ant Ant (โดยไม่ต้องพึ่งพาการจัดการ) เป็นระบบบิลด์ที่ได้รับความนิยมสูงสุดสำหรับโครงการ Java และ JAR ภายนอกทั้งหมดที่โครงการต้องการ (เช่นการพึ่งพาโครงการและการพึ่งพา) ที่จะดาวน์โหลดด้วยตนเองและระบุไว้ในสคริปต์สร้าง

ในทางตรงกันข้าม mockito-core.jar เป็นเพียงคลาส Mockito (เช่นเดียวกับ repackaged ASM และ CGLIB) เมื่อใช้กับ Maven หรือ Gradle การพึ่งพาที่จำเป็น (Hamcrest และ Objenesis) ได้รับการจัดการโดยเครื่องมือเหล่านั้น (ดาวน์โหลดโดยอัตโนมัติและทำการทดสอบแบบพา ธ ) จะช่วยให้แทนที่รุ่นที่ใช้ (ตัวอย่างเช่นถ้าโครงการของเราไม่เคยใช้ แต่เป็นรุ่นที่เข้ากันได้ย้อนหลัง) แต่สิ่งที่สำคัญกว่าการอ้างอิงเหล่านั้นจะไม่ถูกซ่อนอยู่ใน mockito-all.jar สิ่งที่อนุญาตให้ตรวจพบ นี่เป็นวิธีที่ดีกว่ามากเมื่อใช้เครื่องมือที่มีการจัดการการพึ่งพาในโครงการ


0

ในกรณีของฉันฉันต้องแยก hamcrest ที่เก่ากว่าจาก junit-vintage:

<dependency>
  <groupId>org.junit.vintage</groupId>
  <artifactId>junit-vintage-engine</artifactId>
  <scope>test</scope>
  <exclusions>
    <exclusion>
      <groupId>org.hamcrest</groupId>
      <artifactId>hamcrest-core</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<dependency>
  <groupId>org.hamcrest</groupId>
  <artifactId>hamcrest</artifactId>
  <version>2.1</version>
  <scope>test</scope>
</dependency>

0

สิ่งนี้ใช้ได้สำหรับฉัน ไม่จำเป็นต้องแยกสิ่งใด ๆ ออก ฉันเพิ่งใช้mockito-coreแทนmockito-all

testCompile 'junit:junit:4.12'
testCompile group: 'org.mockito', name: 'mockito-core', version: '3.0.0'
testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '2.1'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.