import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.equalTo;
boolean a;
boolean b;
assertThat(a, equalTo(b));
assertThat(a, is(equalTo(b)));
assertThat(a, is(b));
ㅤㅤㅤ
Hamcrest matcher framework tutorial 본문
1. Purpose of the Hamcrest matcher framework
Hamcrest is a framework for software tests. Hamcrest allows checking for conditions in your code via existing matchers classes. It also allows you to define your custom matcher implementations.
Hamcrest는 소프트웨어 테스트를위한 framework입니다. Hamcrest는 기존 matchers 클래스를 통해 코드의 조건을 확인할 수 있습니다. 또한 사용자 정의 matcher implementations 을 정의 할 수 있습니다.
To use Hamcrest matchers in JUnit you use the assertThat
statement followed by one or several matchers.
JUnit에서 Hamcrest matcher를 사용하려면 assertThat 문 뒤에 하나 또는 여러 개의 matchers를 사용합니다.
Hamcrest is typically viewed as a third generation matcher framework. The first generation used assert(logical statement)
but such tests were not easily readable. The second generation introduced special methods for assertions, e.g., assertEquals()
. This approach leads to lots of assert methods. Hamcrest uses assertThat
method with a matcher expression to determine if the test was succesful. See Wiki on Hamcrest for more details.
Hamcrest는 일반적으로 3 세대 정규식 framework로 간주됩니다. 1 세대는 assert(logical statement)을 사용했지만 그러한 테스트는 쉽게 읽을 수 없었습니다. 2 세대에서는 assertEquals()와 같은 assertions을 위한 특수한 메소드가 도입되었습니다. 이 접근법은 많은 assert methods 를 필요로 합니다. Hamcrest는 assertThat 메서드를 사용하여 테스트가 성공적인지 여부를 확인하는 matcher expression을 사용합니다. 자세한 내용은 Hamcrest의 Wiki를 참조하십시오.
Hamcrest has the target to make tests as readable as possible. For example, the is
method is a thin wrapper for equalTo(value)
.
Hamcrest는 최대한 가독성있는 test scripts를 가지는 것을 목표로 하고 있습니다. 예를 들어, is 메소드는 equalTo(value)에 대한 thin wrapper입니다.
The following snippets compare pure JUnit 4 assert statements with Hamcrest matchers.
다음 snippets은 순수 JUnit 4 assert statements와 Hamcrest matchers를 비교합니다.
assertEquals(expected, actual);
assertThat(actual, is(equalTo(expected)));
assertNotEquals(expected, actual)
assertThat(actual, is(not(equalTo(expected))));
It is also possible to chain matchers, via the anyOf
of allOf
method.
allOf 메소드의 anyOf를 통해 matcher를 연결할 수도 있습니다.
assertThat("test", anyOf(is("testing"), containsString("est")));
In general the Hamcrest error messages are also much easier to read.
일반적으로 Hamcrest 오류 메시지는 읽기가 훨씬 쉽습니다.
assertTrue(result instanceof String);
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:86)
at org.junit.Assert.assertTrue(Assert.java:41)
at org.junit.Assert.assertTrue(Assert.java:52)
assertEquals(String.class, result.getClass());
java.lang.NullPointerException
at com.vogella.hamcrest.HamcrestTest.test(HamcrestTest.java:30)
assertThat(result, instanceOf(String.class));
java.lang.AssertionError:
Expected: an instance of java.lang.String
but: null
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8)
Using Hamcrest matchers also provides more type safety as these matchers use generics.
Hamcrest matchers를 사용하면 matcher가 generics를 사용하므로 더 많은 type safety을 제공합니다.
2. Using Hamcrest matchers
2.1. Defining a Hamcrest dependency for Gradle
To use Hamcrest matchers for a project based on the Gradle build system, add the following dependencies to it.
Gradle 빌드 시스템을 기반으로하는 프로젝트에 Hamcrest matchers를 사용하려면 다음 dependencies를 추가하십시오.
dependencies {
'junit:junit:4.12'
testCompile 'org.hamcrest:hamcrest-library:1.3'
}
testCompile
2.2. Defining a Hamcrest dependency for Maven
To use the library for a Maven based project, the following dependency to your pom file.
Maven 기반 프로젝트에 라이브러리를 사용하려면, pom 파일에 다음과 같은 dependencies를 부여하십시오.
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
2.3. Adding Hamcrest directly to the classpath in Eclipse
The JUnit distribution included in Eclipse only contain the core Hamcrest matcher. To use all available matchers, download the latest hamcrest-all-*.jar from https://code.google.com/p/hamcrest/downloads/list and add it to your projects classpath.
Eclipse에 포함 된 JUnit 배포판에는 core Hamcrest matcher 만 포함됩니다. 사용 가능한 모든 matcher를 사용하려면 https://code.google.com/p/hamcrest/downloads/list에서 최신 hamcrest-all - * .jar 파일을 다운로드하여 프로젝트 classpath에 추가하십시오.
If you get the following exception "java.lang.SecurityException: class "org.hamcrest.Matchers"'s signer information does not match signer information of other classes in the same package", ensure that the hamcrest jar is before the Junit library in the build path. You an configure the order in the project properties in the Eclipse IDE under Java Build Path on the Order and Export tab.
"java.lang.SecurityException : class"org.hamcrest.Matchers "의 서명자 정보가 같은 패키지의 다른 클래스의 서명자 정보와 일치하지 않는 경우"hamcrest jar가 Junit 라이브러리보다 앞에 있는지 확인하십시오. 빌드 경로. Eclipse IDE의 프로젝트 특성에서 순서 및 내보내기 탭의 Java 빌드 경로 아래에 순서를 구성하십시오.
3. Using Hamcrest
3.1. Example
The usage of Hamcrest matchers is demonstrates by the following code snippet.
Hamcrest matchers의 사용법은 다음 code snippet을 통해 보여줍니다.
assertThat(Long.valueOf(1), instanceOf(Integer.class));
assertThat(Long.valueOf(1), isA(Integer.class));
3.2. Static import
To make all matchers available in your file add an static import. This also makes it easier to find matchers through code completion.
파일에서 모든 matcher를 사용할 수 있게 하려면 static import를 추가하십시오. 이러면 code completion을 통해 matcher를 쉽게 찾을 수 있도록 해 주기도 합니다.
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
3.3. Hamcrest matchers for lists
The usage of the Hamcrest matchers for lists are demonstrated by the following example.
lists에 대한 Hamcrest matchers의 사용법은 다음 예제에서 보여 줍니다.
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.hamcrest.core.Every.everyItem;
public class HamcrestListMatcherExamples {
@Test
public void listShouldInitiallyBeEmpty() {
List<Integer> list = Arrays.asList(5, 2, 4);
assertThat(list, hasSize(3));
assertThat(list, contains(5, 2, 4));
assertThat(list, containsInAnyOrder(2, 4, 5));
assertThat(list, everyItem(greaterThan(1)));
}
}
"race", is(not((ORC))))));
assertThat(fellowship, everyItem(hasProperty(
3.4. Overview of Hamcrest mather
The following are the most important Hamcrest matchers:
다음은 가장 중요한 Hamcrest matchers들 입니다.
allOf
- matches if all matchers match (short circuits)anyOf
- matches if any matchers match (short circuits)not
- matches if the wrapped matcher doesn’t match and viceequalTo
- test object equality using the equals methodis
- decorator for equalTo to improve readabilityhasToString
- test Object.toStringinstanceOf
,isCompatibleType
- test typenotNullValue
,nullValue
- test for nullsameInstance
- test object identityhasEntry
,hasKey
,hasValue
- test a map contains an entry, key or valuehasItem
,hasItems
- test a collection contains elementshasItemInArray
- test an array contains an elementcloseTo
- test floating point values are close to a given valuegreaterThan
,greaterThanOrEqualTo
,lessThan
,lessThanOrEqualTo
equalToIgnoringCase
- test string equality ignoring caseequalToIgnoringWhiteSpace
- test string equality ignoring differences in runs of whitespacecontainsString
,endsWith
,startsWith
- test string matching
4. Exercise - Writing a custom Hamcrest matcher using FeatureMatcher
4.1. Target
The target of this exercise is to write a custom matcher with Hamcrest.
이 exercise의 목표는 Hamcrest 에서 custom matcher를 작성하는 것입니다.
4.2. Create Hamcrest Matchers
Define a custom matcher for Hamcrest which provides the length
matcher for a String. We want to use the class FeatureMatcher
. With FeatureMatcher we can wrap an existing Matcher, decide which field of the given Object under test to match and provide a nice error message. The constructor of FeatureMatcher takes the following arguments in this order:
Hamcrest를위한 custom matcher를 정의하여 String에 대한 length matcher를 제공합니다. 우리는 FeatureMatcher 클래스를 사용하고자합니다. FeatureMatcher를 사용하면 기존 Matcher를 wrap하고 테스트 할 대상 객체의 필드를 결정하여 나은 오류 메시지를 제공 할 수 있습니다. FeatureMatcher의 생성자는 다음 순서로 인수를 취합니다.
The matcher we want to wrap
a description of the feature that we tested
a description of the possible mismatch
The only method we have to overwrite is featureValueOf(T actual)
which returns the value which will get passed into the wrapped matches()
/matchesSafely()
method.
overwrite하는 유일한 방법은 wrapped matches () / matchesSafely () 메서드에 전달 될 값을 반환하는 featureValueOf (T actual)입니다.
public static Matcher<String> length(Matcher<? super Integer> matcher) {
return new FeatureMatcher<String, Integer>(matcher, "a String of length that", "length") {
@Override
protected Integer featureValueOf(String actual) {
return actual.length();
}
};
}
4.3. Validate
Use your custom matcher to check that "Gandalf" has a lenght of 8.
Gandalf의 길이가 8인지에 대해 여러분의 custom matcher 를 사용해서 확인해 보세요.
@Test
public void fellowShipOfTheRingShouldContainer7() {
assertThat("Gandalf", length(is(8)));
}
public static Matcher<String> length(Matcher<? super Integer> matcher) {
return new FeatureMatcher<String, Integer>(matcher, "a String of length that", "length") {
@Override
protected Integer featureValueOf(String actual) {
return actual.length();
}
};
}
5. Exercise: Writing your custom Hamcrest matcher using TypeSafeMatcher
It is possible to write your custom Hamcrest matcher by extending TypeSafeMatcher. In contrast to BaseMatcher the TypeSafeMatcher class automatically checks for null
values, checks the type and casts appropriately before delegating to matchesSafely()
. It provides type safety by default. The following is an example for defining a matcher which allows testing if a String matches a regular expression.
TypeSafeMatcher를 extends하여 custom Hamcrest matcher를 작성할 수 있습니다. BaseMatcher와 달리 TypeSafeMatcher 클래스는 자동으로 null 값을 확인하고, types를 검사하고 matchesSafely ()에 위임하기 전에 적절하게 형 변환합니다. 기본적으로 type safety 을 제공합니다. 다음은 문자열이 정규 표현식 regular expression 과 일치하는지 테스트 할 수있는 matcher를 정의하는 예제입니다.
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
public class RegexMatcher extends TypeSafeMatcher<String> {
private final String regex;
public RegexMatcher(final String regex) {
this.regex = regex;
}
@Override
public void describeTo(final Description description) {
description.appendText("matches regular expression=`" + regex + "`");
}
@Override
public boolean matchesSafely(final String string) {
return string.matches(regex);
}
public static RegexMatcher matchesRegex(final String regex) {
return new RegexMatcher(regex);
}
}
The following snippet gives an example how to use it.
다음 snippet에는 이를 사용하는 예가 나와 있습니다.
package com.vogella.android.testing.applicationtest;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
public class TestCustomMatcher {
@Test
public void testRegularExpressionMatcher() throws Exception {
String s ="aaabbbaaaa";
assertThat(s, RegexMatcher.matchesRegex("a*b*a*"));
}
}
6. Exercise: Combining matchers
Combining matchers is supported by Hamcrest out of the box but it has the limitation that the error is hard to read:
matchers를 결합하는 것은 Hamcrest에 오류가 읽기 어렵다는 제한이 있습니다.
@Test
public void () {
List<Integer> list = new ArrayList<>();
assertThat(list, both(hasSize(1)).and(contains(42)));
}
Expected: (a collection with size <1> and iterable containing [<42>])
but: a collection with size <1> collection size was <0>.
This not very readable.
이렇게 가독성이 떨어집니다.
6.1. Target
We want to write our own MatcherCombiner that provides us with a readable error message, even when multiple matchers fail.
우리는 multiple matchers가 fail하더라도 가독성있는 에러 메시지를 제공하는 MatcherCombiner를 별도로 작성하려고합니다.
6.2. Create MatchCombiner
We do this by inheriting from BaseMatch and by providing a starting method that let’s us chain matchers together. The matchers get saved in a list that we iterate over during the matching phase.
우리는 BaseMatch로부터 상속하고 chain matcher를 함께 묶어주는 것을 시작하면서 이 작업을 수행합니다. matchers는 matching phase 동안에 반복되는 list 저장됩니다.
public class MatcherCombinator<T> extends BaseMatcher<T> {
private final List<Matcher<? super T>> matchers = new ArrayList<>();
private final List<Matcher<? super T>> failedMatchers = new ArrayList<>();
private MatcherCombinator(final Matcher<? super T> matcher) {
matchers.add(matcher);
}
public MatcherCombinator<T> and(final Matcher<? super T> matcher) {
matchers.add(matcher);
return this;
}
@Override
public boolean matches(final Object item) {
boolean matchesAllMatchers = true;
for (final Matcher<? super T> matcher : matchers) {
if (!matcher.matches(item)) {
failedMatchers.add(matcher);
matchesAllMatchers = false;
}
}
return matchesAllMatchers;
}
@Override
public void describeTo(final Description description) {
description.appendValueList("\n", " " + "and" + "\n", "", matchers);
}
@Override
public void describeMismatch(final Object item, final Description description) {
description.appendText("\n");
for (Iterator<Matcher<? super T>> iterator = failedMatchers.iterator(); iterator.hasNext();) {
final Matcher<? super T> matcher = iterator.next();
description.appendText("Expected: <");
description.appendDescriptionOf(matcher).appendText(" but ");
matcher.describeMismatch(item, description);
if (iterator.hasNext()) {
description.appendText(">\n");
}
}
}
public static <LHS> MatcherCombinator<LHS> matches(final Matcher<? super LHS> matcher) {
return new MatcherCombinator<LHS>(matcher);
}
}
To validate the implementation we write a new test.
implementation을 validate하기 위해 새로운 테스트를 작성합니다.
@Test
public void test() {
List<Integer> list = new ArrayList<>();
assertThat(list, matches(hasSize(1)).and(contains(42)));
}
java.lang.AssertionError:
Expected:
<a collection with size <1>> and
<iterable containing [<42>]>
but:
Expected: <a collection with size <1> but collection size was <0>>
Expected: <iterable containing [<42>] but No item matched: <42>.
You can adjust this output in the describeMismatch
method.
describeMismatch
method 에서 이 output을 adjust 할 수 있습니다.
7. Grouping your matchers for import
If you define many custom matchers it might become tedious to import them one by one into your test files. By grouping them into a single class you can import them with one statement. You can also group them together with Hamcrest matchers.
많은 custom matchers를 정의하면 테스트 파일에 하나씩 import하는 것이 불편 할 수 있습니다. single class로 그룹화하여 하나의 statement로 가져올 수 있습니다. Hamcrest matchers와 함께 그룹화 할 수도 있습니다.
package com.vogella.hamcrest;
import com.vogella.hamcrest.matchers.RegexMatcher;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
public class MyMatchers
{
public static <T> Matcher<T> instanceOf(Class<T> target) {
return Matchers.instanceOf(target);
}
public static Matcher<String> matchesRegex(String target) {
return RegexMatcher.matchesRegex(target);
}
}
In your test file:
import static com.vogella.hamcrest.MyMatchers.*;
출처: http://coronasdk.tistory.com/918 [IT 기술 따라잡기]
출처 : http://bluebreeze.co.kr/508
Hamcrest : 비교표현확장
Hamcrest(햄크레스트)는 jMock이라는 Mock 라이브러리 저자들이 참여해 만들고 있는Matcher 라이브러리입니다.
테스트 표현식을 작성할 때 좀 더 문맥적으로 자연스럽고, 우아한 문장을 만들 수 있게 도와줍니다.
개발자만이 읽을 수 있는 프로그램밍 언어라라는 느낌보다 좀 더 문장체에 가까운 느낌으로 넓은 범주의 사람들이 함께 이해할 수 있는 형태로 만들어줍니다.
현재 Hamcrest는 Java 이외에도 C++, Objective-C, Phthon 그리고 PHP 버전으로도 포팅되어 있습니다.
Matcher 라이브러리: 필터나 검색등을 위해 값을 비교할 때 좀 더 편리하게 시용할 수 있게 도와주는 라이브러리입니다.
Hamcrest 라이브러리는 기본적으로 assertEquals 대신에 assertThat이라는 구분사용을 권장한다.
공학적인 느낌을 주는 딱딱한 assertEquals 보다는 assertThat이 좀 더 문맥적인 흐르을 만들어준다고 여기기 때문입니다. ( 영어라서 이해를 못하겠습니다. ㅜ.ㅜ)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | asertEquals( "YoungJim" , customer.getName() ); assertThat( customer.getName(), is( "YoungJim" ) ); // 적용 전 assertEquals( 100 , account.getBalance()); // 적용 후 aseertThat(account.getBalance(), is(equalTo( 10000 ))); // 적용 전 assertNotNull(resorce.newConnection()); // 적용 후 assertThat(resource.newConection(), is(notNullValue()); // 적용 전 assertTrue(account.getBalance() > 0 ); // 적용 후 assertThat(account.getBalance(), isGreaterThan( 0 )); // 적용 전 assertTrue(user.getloginName().indexOf( "Guest" ) > - 1 ); // 적용 후 asertThat(user.getLoginName(), containsString( "Guest" )); |
1 2 3 4 5 6 7 8 9 10 | import static org.junit.Assert.*; import static org.hamcrest.CoreMatchers.*; import org.junit.Test; public class HamcrestTest{ @Test public void testArray() throws Exception { assertThat( "Start Date 비교" , "2010/02/03" , is( "2010/02/04" )); } } |
패키지 | 설명 |
---|---|
org.hamcrest.core | 오브젝트나 값들에 대한 기본적인 Matcher들 |
org.hamcrest.beans | Java 빈(Bean)과 그 값 비교에 사용되는 Matcher들 |
org.hamcrest.coolection | 배열과 컬렉션 Matcher들 |
org.hamcrest.number | 수 비교를 하기 위한 Matcher들 |
org.hamcrest.object | 오브젝트와 클래스들 비교하는 Matcher들 |
org.hamcrest.test | 문자열 비교 |
org.hamcrest.xml | XML 문서 비교 |
- 코어(Core)
메소드 설명 클래스 명 anything 어떤 오브젝트가 사용되든 일치한다고 판별한다. IsAnything describedAs 테스트 실패 시에 보여줄 추가적인 메시지를 만들어주는 메시지 테코레이터 DescribedAs equalTo 두 오브텍트가 동일한지 판별한다. IsEqual is 내부적으로 equalTo와 동일하다.
가독성 증진용.
아래 세문장은 의미가 동일하다.
[code java]assertThat(entity, equalTo(expectedEntity));
assertThat(entity, is(equalTo(expectedEntity)));
assertThat(entity, is(expectedEntity));
[/code]Is - 오브젝트(Object)
메소드 설명 클래스 명 hasToString toString 메소드 값과 일치 여부를 판별한다. HasToString instanceOf
typeCompatibleWith동일 인스턴스인지 타입비교(instance of).
동일하거나 상위 클래스, 인터페이스인지 판별IsInstanceOf
IsCompatibleTypenotNullValue
nullValueNull인지, 아닌지 판별 IsNull sameInstance Object가 완전히 동일한지 비교.
equals 비교가 아닌 ==(주소비교)로 비교하는 것과 동일isSame - 논리(Logical)
메소드 설명 클래스 명 allOf 비교하는 두 오브젝트가 각각 여러 개의 다른 오브젝트를 포함하고 있을 경우에, 이를테면 collection 같은 오브젝트일 경우 서로 동일한지 판별한다. Java의 숏서킷(&& 비교)과 마찬가지로 한 부분이라도 다른 부분이 나오면 그 순간 false를 돌려준다. AllOf anyOf allOf와 비슷하나 anyOf는 하나라도 일치하는 것이 나오면 true로 판단한다.
Java의 숏서킷(||)과 마찬가지로 한 번이라도 일치하면 true를 돌려준다.AnyOf not 서로 같지 않아야 한다. IsNot - 빈즈(Beans)
메소드 설명 클래스 명 hasProperty Java 빈즈 프로퍼티 테스트 HasProperty - 컬렉션(Collection)
메소드 설명 클래스 명 array 두 배열 내의 요소가 모두 일치하는지 판별 IsArray hasEntry, hasKey, hasValue 맴(Map)요소에 대한 포함 여부 판단 isMapContaining hasItem, hasItems 특정 요소들을 포함하고 있는지 여부 판단 IsCollectionContaining hasItemInArray 배열 내에 찾는 대상이 들어 있는지 여부를 판별 IsArrayContaining - 숫자(Number)
메소드 설명 클래스 명 closeTo 부동소수점(floating point) 값에 대한 근사값 내 일치 여부, 값(value)과 오차(delta)를 인자로 갖는다. IsCloseTo greaterThan
greaterThanOrEqualTo값 비교. >, >= OrderingComparison lessThan
lessThanOrEqualTo값 비교. <, <= OrderingComparison - 텍스트(Text)
메소드 설명 클래스 명 containsString 문자열이 포함되어 있는지 여부 StringContains startsWith 특정 문자열로 시작 StringStartsWith endsWith 특정 문자열로 종료 StringEndsWith equalToIgnoringCase 대소문자 구분하지 않고 문자비교 IsEqualIgnoringCase equalToIgnoringWithSpace 문자열 사이의 공백 여부를 구분하지 않고 비교 IsEqualIgnoringWhiteSpace
'プログラミング > TDD' 카테고리의 다른 글
Hamcrest matchers list (0) | 2017.06.07 |
---|---|
JAVA Project Hamcrest 라이브러리 추가하는 법 (0) | 2017.06.07 |
JUnit 기본 참고 자료 (0) | 2017.06.07 |
JUnit Tutorial (0) | 2017.06.07 |