如何同时使用 jUnit 和 Hamcrest?

我不能理解 JUnit 4.8如何与 Hamcrest 匹配器一起工作。在 org.hamcrest.CoreMatchers中的 junit-4.8.jar中定义了一些匹配器。同时,在 org.hamcrest.Matchershamcrest-all-1.1.jar中也存在一些 其他匹配子。那么,去哪里?我应该明确地将 hamcrest JAR 包含到项目中并忽略 JUnit 提供的匹配器吗?

特别是,我感兴趣的 empty()匹配器,不能找到这些罐子中的任何一个。我还需要别的吗?:)

还有一个哲学问题: 为什么 JUnit 在自己的发行版中包含 org.hamcrest包,而不是鼓励我们使用原始的 Hamcrest 库?

70404 次浏览

junit provides new check assert methods named assertThat() which uses Matchers and should provide a more readable testcode and better failure messages.

To use this there are some core matchers included in junit. You can start with these for basic tests.

If you want to use more matchers you can write them by yourself or use the hamcrest lib.

The following example demonstrates how to use the empty matcher on an ArrayList:

package com.test;


import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;


import java.util.ArrayList;
import java.util.List;


import org.junit.Test;


public class EmptyTest {
@Test
public void testIsEmpty() {
List myList = new ArrayList();
assertThat(myList, is(empty()));


}
}

(I included the hamcrest-all.jar in my buildpath)

Not exactly answering your question, but you should definitely try FEST-Assert fluent assertions API. It's competing with Hamcrest, but has a much easier API with only one static import required. Here is the code provided by cpater using FEST:

package com.test;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import static org.fest.assertions.Assertions.assertThat;


public class EmptyTest {
@Test
public void testIsEmpty() {
List myList = new ArrayList();
assertThat(myList).isEmpty();
}
}

EDIT: Maven coordinates:

<dependency>
<groupId>org.easytesting</groupId>
<artifactId>fest-assert</artifactId>
<version>1.4</version>
<scope>test</scope>
</dependency>

why JUnit included org.hamcrest package into its own distribution instead of encouraging us to use original hamcrest library?

I would guess that's because they wanted the assertThat to be part of JUnit. So that means the Assert class has to import the org.hamcrest.Matcher interface and it can't do that unless JUnit either depends on Hamcrest, or includes (at least part of) Hamcrest. And I guess including part of it was easier, so that JUnit would be usable without any dependencies.

If you're using a Hamcrest with a version greater or equal than 1.2, then you should use the junit-dep.jar. This jar has no Hamcrest classes and therefore you avoid classloading problems.

Since JUnit 4.11 the junit.jar itself has no Hamcrest classes. There is no need for junit-dep.jar anymore.

Also, if JUnit 4.1.1 + Hamcrest 1.3 + Mockito 1.9.5 are being used, make sure mockito-all is not used. It contains Hamcrest core classes. Use mockito-core instead. The below config works :

<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>hamcrest-core</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.1.1</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>hamcrest-core</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
</exclusions>
</dependency>

Since versions are changing all the time, I'm posting to let people know that as of December 2, 2014, the instructions at http://www.javacodegeeks.com/2014/03/how-to-test-dependencies-in-a-maven-project-junit-mockito-hamcrest-assertj.html worked for me. I did not use AssertJ though, just these:

<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.9.5</version>
<scope>test</scope>
</dependency>
<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.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>

Both JUnit-4.12 and JUnit-Dep-4.10 has Hamcrest dependencies according to the respective .xml files.

Further investigation shows that although the dependency was made in the .xml files, the source and classes in the jars. The seems to be a way of excluding the dependency in build.gradle ... testing it out to keep everything clean.

Just an f.y.i.

In 2018 using most modern libraries:

configurations {
all {
testCompile.exclude group: "org.hamcrest", module: "hamcrest-core"
testCompile.exclude group: "org.hamcrest", module: "hamcrest-library"
}
}
dependencies {
testCompile("junit:junit:4.12")
// testCompile("org.hamcrest:hamcrest-library:1.3")
// testCompile("org.hamcrest:java-hamcrest:2.0.0.0")
testCompile("org.hamcrest:hamcrest-junit:2.0.0.0")
}