Hamcrest Tutorial
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:
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
public class BiscuitTest {
@Test
public void testEquals() {
Biscuit theBiscuit = new Biscuit("Ginger");
Biscuit myBiscuit = new Biscuit("Ginger");
assertThat(theBiscuit, equalTo(myBiscuit));
}
}
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:
assertThat("chocolate chips", theBiscuit.getChocolateChipCount(), equalTo(10));
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:
assertThat(theBiscuit, equalTo(myBiscuit));
assertThat(theBiscuit, is(equalTo(myBiscuit)));
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:
@Test
public void testSquareRootOfMinusOneIsNotANumber() {
assertThat(Math.sqrt(-1), is(notANumber()));
}
And here’s the implementation:
package org.hamcrest.examples.tutorial;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
public class IsNotANumber extends TypeSafeMatcher {
@Override
public boolean matchesSafely(Double number) {
return number.isNaN();
}
public void describeTo(Description description) {
description.appendText("not a number");
}
public static Matcher notANumber() {
return new IsNotANumber();
}
}
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:
assertThat(1.0, is(notANumber()));
// fails with the message
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:
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.examples.tutorial.IsNotANumber.notANumber;
public class NumberTest {
@Test
public void testSquareRootOfMinusOneIsNotANumber() {
assertThat(Math.sqrt(-1), is(notANumber()));
}
}
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.
</div>
Hamcrest Tutorial的更多相关文章
- Hamcrest使用
What is Hamcrest? 什么是Hamcrest? Hamcrest is a library of matchers, which can be combined in to crea ...
- [翻译+山寨]Hangfire Highlighter Tutorial
前言 Hangfire是一个开源且商业免费使用的工具函数库.可以让你非常容易地在ASP.NET应用(也可以不在ASP.NET应用)中执行多种类型的后台任务,而无需自行定制开发和管理基于Windows ...
- Django 1.7 Tutorial 学习笔记
官方教程在这里 : Here 写在前面的废话:)) 以前学习新东西,第一想到的是找本入门教程,按照书上做一遍.现在看了各种网上的入门教程后,我觉得还是看官方Tutorial靠谱.书的弊端一说一大推 本 ...
- thrift 服务端linux C ++ 与客户端 windows python 环境配置(thrift 自带tutorial为例)
关于Thrift文档化的确是做的不好.摸索了很久才终于把跨linux与windows跨C++与python语言的配置成功完成.以下是步骤: 1) Linux下环境配置 ...
- Hive Tutorial(上)(Hive 入门指导)
用户指导 Hive 指导 Hive指导 概念 Hive是什么 Hive不是什么 获得和开始 数据单元 类型系统 内置操作符和方法 语言性能 用法和例子(在<下>里面) 概念 Hive是什么 ...
- 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 ...
- Using FreeMarker templates (FTL)- Tutorial
Lars Vogel, (c) 2012, 2016 vogella GmbHVersion 1.4,06.10.2016 Table of Contents 1. Introduction to F ...
- 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 ...
- Tutorial - Deferred Rendering Shadow Mapping 转
http://www.codinglabs.net/tutorial_opengl_deferred_rendering_shadow_mapping.aspx Tutorial - Deferred ...
随机推荐
- mysql自定义function 写递归查询子节点
#存储文本信息表 CREATE TABLE WordInfoEntity( word_id ) PRIMARY KEY NOT NULL, # 主键ID UUID word_greda :正文文本 , ...
- 【Java-加密算法】对称加密、非对称加密、单向散列(转)
一提到加密,就会联想到数字签名,这两个经常被混淆的概念到底是什么呢? 加密:加密是一种以密码方式发送信息的方法.只有拥有正确密钥的人才能解开这个信息的密码.对于其他人来说,这个信息看起来就像是一系列随 ...
- 如何用好消息推送(push)做APP运营
作为移动端APP产品运营最重要的运营手段,消息推送(push)被越来越多的APP厂商所重视,在信息泛滥的移动互联网时代,手机APP应用安装得越来越多,小小的手机屏幕每天收到的消息推送也越来越多,站在用 ...
- 开通了第一个博客,mark一下!
今日上网查询了不同的博客,包括csdn.掘金等,最终决定选择博客园.打算待前端学完后,自己建立一个博客,这段时间内先用博客园记录学习过程.经常总结.更新,相信坚持学习一定可以找到好工作!
- 【JZOJ4359】【GDKOI2016】魔卡少女
题目描述 君君是中山大学的四年级学生.有一天在家不小心开启了放置在爸爸书房中的一本古书.于是,君君把放在书中最上面的一张牌拿出来观摩了一下,突然掀起一阵大风把书中的其她所有牌吹散到各地.这时一只看上去 ...
- java中URLEncode和URLDecode
URLEncode和URLDecode用于完成普通字符串和 application/x-www-from-urlencoded MIME字符串之间的相互转化 如果传递的字符串中包含非西欧字符的字符串, ...
- 如何用django框架完整的写一个项目
实现目标及功能,增删改,并且实现搜索,分页,日期插件,删除提示,以及批量导入等功能 软件版本: python3.5 django1.11 一 用pycharm创建一个项目,名字自定义 二 编辑url ...
- python 嵌套列表
- oracle函数 to_single_byte(c1)
[功能]将字符串中的全角转化为半角 [参数]c1,字符型 [返回]字符串 [示例] SQL> select to_multi_byte('高A') text from dual; test -- ...
- javascript实现html中关键字查询
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...