Java Hamcrest Home

Hamcrest Tutorial

Introduction

Hamcrest is a framework for writing matcher objects allowing ‘match’ rules to be defined declaratively. There are a number of situations where matchers are invaluble, such as UI validation, or data filtering, but it is in the area of writing flexible tests that matchers are most commonly used. This tutorial shows you how to use Hamcrest for unit testing.

When writing tests it is sometimes difficult to get the balance right between overspecifying the test (and making it brittle to changes), and not specifying enough (making the test less valuable since it continues to pass even when the thing being tested is broken). Having a tool that allows you to pick out precisely the aspect under test and describe the values it should have, to a controlled level of precision, helps greatly in writing tests that are “just right”. Such tests fail when the behaviour of the aspect under test deviates from the expected behaviour, yet continue to pass when minor, unrelated changes to the behaviour are made.

My first Hamcrest test

We’ll start by writing a very simple JUnit 5 test, but instead of using JUnit’s assertEquals methods, we use Hamcrest’s assertThat construct and the standard set of matchers, both of which we statically import:

  1. import org.junit.jupiter.api.Test;
  2. import static org.hamcrest.MatcherAssert.assertThat;
  3. import static org.hamcrest.Matchers.*;
  4. public class BiscuitTest {

  5. @Test

  6. public void testEquals() {

  7. Biscuit theBiscuit = new Biscuit("Ginger");

  8. Biscuit myBiscuit = new Biscuit("Ginger");

  9. assertThat(theBiscuit, equalTo(myBiscuit));

  10. }

  11. }

The assertThat method is a stylized sentence for making a test assertion. In this example, the subject of the assertion is the object biscuit that is the first method parameter. The second method parameter is a matcher for Biscuit objects, here a matcher that checks one object is equal to another using the Object equals method. The test passes since the Biscuit class defines an equals method.

If you have more than one assertion in your test you can include an identifier for the tested value in the assertion:

  1. assertThat("chocolate chips", theBiscuit.getChocolateChipCount(), equalTo(10));
  2. assertThat("hazelnuts", theBiscuit.getHazelnutCount(), equalTo(3));

Other test frameworks

Hamcrest has been designed from the outset to integrate with different unit testing frameworks. For example, Hamcrest can be used with JUnit (all versions) and TestNG. (For details have a look at the examples that come with the full Hamcrest distribution.) It is easy enough to migrate to using Hamcrest-style assertions in an existing test suite, since other assertion styles can co-exist with Hamcrest’s.

Hamcrest can also be used with mock objects frameworks by using adaptors to bridge from the mock objects framework’s concept of a matcher to a Hamcrest matcher. For example, JMock 1’s constraints are Hamcrest’s matchers. Hamcrest provides a JMock 1 adaptor to allow you to use Hamcrest matchers in your JMock 1 tests. JMock 2 doesn’t need such an adaptor layer since it is designed to use Hamcrest as its matching library. Hamcrest also provides adaptors for EasyMock 2. Again, see the Hamcrest examples for more details.

A tour of common matchers

Hamcrest comes with a library of useful matchers. Here are some of the most important ones.

Core

anything - always matches, useful if you don’t care what the object under test is

describedAs - decorator to adding custom failure description

is - decorator to improve readability - see “Sugar”, below

Logical

allOf - matches if all matchers match, short circuits (like Java &&)

anyOf - matches if any matchers match, short circuits (like Java   )

not - matches if the wrapped matcher doesn’t match and vice versa

Object

equalTo - test object equality using Object.equals

hasToString - test Object.toString

instanceOf, isCompatibleType - test type

notNullValue, nullValue - test for null

sameInstance - test object identity

Beans

hasProperty - test JavaBeans properties

Collections

array - test an array’s elements against an array of matchers

hasEntry, hasKey, hasValue - test a map contains an entry, key or value

hasItem, hasItems - test a collection contains elements

hasItemInArray - test an array contains an element

Number

closeTo - test floating point values are close to a given value

greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo - test ordering

Text

equalToIgnoringCase - test string equality ignoring case

equalToIgnoringWhiteSpace - test string equality ignoring differences in runs of whitespace

containsString, endsWith, startsWith - test string matching

Sugar

Hamcrest strives to make your tests as readable as possible. For example, the is matcher is a wrapper that doesn’t add any extra behavior to the underlying matcher. The following assertions are all equivalent:

  1. assertThat(theBiscuit, equalTo(myBiscuit));
  2. assertThat(theBiscuit, is(equalTo(myBiscuit)));
  3. assertThat(theBiscuit, is(myBiscuit));

The last form is allowed since is(T value) is overloaded to return is(equalTo(value)).

Writing custom matchers

Hamcrest comes bundled with lots of useful matchers, but you’ll probably find that you need to create your own from time to time to fit your testing needs. This commonly occurs when you find a fragment of code that tests the same set of properties over and over again (and in different tests), and you want to bundle the fragment into a single assertion. By writing your own matcher you’ll eliminate code duplication and make your tests more readable!

Let’s write our own matcher for testing if a double value has the value NaN (not a number). This is the test we want to write:

  1. @Test
  2. public void testSquareRootOfMinusOneIsNotANumber() {
  3. assertThat(Math.sqrt(-1), is(notANumber()));
  4. }

And here’s the implementation:

  1. package org.hamcrest.examples.tutorial;
  2. import org.hamcrest.Description;

  3. import org.hamcrest.Matcher;

  4. import org.hamcrest.TypeSafeMatcher;
  5. public class IsNotANumber extends TypeSafeMatcher {
  6. @Override

  7. public boolean matchesSafely(Double number) {

  8. return number.isNaN();

  9. }
  10. public void describeTo(Description description) {

  11. description.appendText("not a number");

  12. }
  13. public static Matcher notANumber() {

  14. return new IsNotANumber();

  15. }
  16. }

The assertThat method is a generic method which takes a Matcher parameterized by the type of the subject of the assertion. We are asserting things about Double values, so we know that we need a Matcher<Double>. For our Matcher implementation it is most convenient to subclass TypeSafeMatcher, which does the cast to a Double for us. We need only implement the matchesSafely method - which simply checks to see if the Double is NaN - and the describeTo method - which is used to produce a failure message when a test fails. Here’s an example of how the failure message looks:

  1. assertThat(1.0, is(notANumber()));
  2. // fails with the message
  3. java.lang.AssertionError: Expected: is not a number got : <1.0>

The third method in our matcher is a convenience factory method. We statically import this method to use the matcher in our test:

  1. import org.junit.jupiter.api.Test;
  2. import static org.hamcrest.MatcherAssert.assertThat;
  3. import static org.hamcrest.Matchers.*;
  4. import static org.hamcrest.examples.tutorial.IsNotANumber.notANumber;
  5. public class NumberTest {

  6. @Test

  7. public void testSquareRootOfMinusOneIsNotANumber() {

  8. assertThat(Math.sqrt(-1), is(notANumber()));

  9. }

  10. }

Even though the notANumber method creates a new matcher each time it is called, you should not assume this is the only usage pattern for your matcher. Therefore you should make sure your matcher is stateless, so a single instance can be reused between matches.

  1. </div>

原文地址:http://hamcrest.org/JavaHamcrest/tutorial

Hamcrest Tutorial的更多相关文章

  1. Hamcrest使用

    What is Hamcrest? 什么是Hamcrest?   Hamcrest is a library of matchers, which can be combined in to crea ...

  2. [翻译+山寨]Hangfire Highlighter Tutorial

    前言 Hangfire是一个开源且商业免费使用的工具函数库.可以让你非常容易地在ASP.NET应用(也可以不在ASP.NET应用)中执行多种类型的后台任务,而无需自行定制开发和管理基于Windows ...

  3. Django 1.7 Tutorial 学习笔记

    官方教程在这里 : Here 写在前面的废话:)) 以前学习新东西,第一想到的是找本入门教程,按照书上做一遍.现在看了各种网上的入门教程后,我觉得还是看官方Tutorial靠谱.书的弊端一说一大推 本 ...

  4. thrift 服务端linux C ++ 与客户端 windows python 环境配置(thrift 自带tutorial为例)

    关于Thrift文档化的确是做的不好.摸索了很久才终于把跨linux与windows跨C++与python语言的配置成功完成.以下是步骤: 1)                 Linux下环境配置 ...

  5. Hive Tutorial(上)(Hive 入门指导)

    用户指导 Hive 指导 Hive指导 概念 Hive是什么 Hive不是什么 获得和开始 数据单元 类型系统 内置操作符和方法 语言性能 用法和例子(在<下>里面) 概念 Hive是什么 ...

  6. Home / Python MySQL Tutorial / Calling MySQL Stored Procedures in Python Calling MySQL Stored Procedures in Python

    f you are not familiar with MySQL stored procedures or want to review it as a refresher, you can fol ...

  7. Using FreeMarker templates (FTL)- Tutorial

    Lars Vogel, (c) 2012, 2016 vogella GmbHVersion 1.4,06.10.2016 Table of Contents 1. Introduction to F ...

  8. Oracle Forms 10g Tutorial Ebook Download - Oracle Forms Blog

    A step by step tutorial for Oracle Forms 10g development. This guide is helpful for freshers in Orac ...

  9. Tutorial - Deferred Rendering Shadow Mapping 转

    http://www.codinglabs.net/tutorial_opengl_deferred_rendering_shadow_mapping.aspx Tutorial - Deferred ...

随机推荐

  1. phpexcel使用说明3

    下面是总结的几个使用方法 include 'PHPExcel.php'; include 'PHPExcel/Writer/Excel2007.php'; //或者include 'PHPExcel/ ...

  2. SELinux 宽容模式(permissive) 强制模式(enforcing) 关闭(disabled) 几种模式之间的转换

    http://blog.sina.com.cn/s/blog_5aee9eaf0100y44q.html 在CentOS6.2 中安装intel 的c++和fortran 的编译器时,遇到来一个关于S ...

  3. 微信小程序入门到实战(1)-基础知识

    1.微信小程序介绍 微信小程序,简称小程序,英文名Mini Program,是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或搜一下即可打开应用. 1.1. 为什么是微信 ...

  4. jQuery 鼠标移入图片 显示大图并跟随鼠标移动

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. UVa 825【简单dp,递推】

    UVa 825 题意:给定一个网格图(街道图),其中有一些交叉路口点不能走.问从西北角走到东南角最短走法有多少种.(好像没看到给数据范围...) 简单的递推吧,当然也就是最简单的动归了.显然最短路长度 ...

  6. qt 在ui界面添加控件后在cpp文件中无法调用?

    问题:qt 在ui界面添加控件后在cpp文件中无法调用? 解决方法:在build选项中选择“重新build项目”,再次在cpp中调用添加的控件发现可以调用了. 还有一种情况导致添加控件后无法调用,就是 ...

  7. list extend 和 append

    append 一次追加一个列表 extend 一次追加所有的元素 单个的形式加入

  8. 一线实践 | 借助混沌工程工具 ChaosBlade 构建高可用的分布式系统

    在分布式架构环境下,服务间的依赖日益复杂,可能没有人能说清单个故障对整个系统的影响,构建一个高可用的分布式系统面临着很大挑战.在可控范围或环境下,使用 ChaosBlade 工具,对系统注入各种故障, ...

  9. 模板—K-D-tree(P2479 [SDOI2010]捉迷藏)

    #include<algorithm> #include<iostream> #include<cstdio> #include<cmath> #def ...

  10. PHP中__FUNCTION__与__METHOD__的区别

    你知道php中__FUNCTION__与__METHOD__的区别吗?本文通过一个小例子,为大家介绍下二者的区别,有兴趣的朋友可以参考下.   PHP中__FUNCTION__与__METHOD__的 ...