martes, noviembre 23, 2010

... Una Vez Está Bien Pero Dos Está Mal ...

Hamcrest is about making your test readable. Hamcrest is a framework that allows us to use object matchers for developing stylized sentences in assertions.

Let's look some examples:

Why write this:

double calculatedValue = 1000D;
...
assertEquals(1000, calculatedValue, 0)


When you can write this:

assertThat(calculatedValue, is(1000));

Or Why write off all this code:

List validResults = Arrays.asList("4+", "3+", "2+");
String result = .....;

assertFalse(validResults.contains(result));


When you can write:

assertThat("1+", not(isIn(validResults)));

Three points should get your attention:

I. Using assertEquals (in our case with double) is not readable, what is the meaning of third parameter in previous example ?¿ What's happen if instead of 0 I pass a 1?¿.

II. When you speak yourself repeating a requirement, you say: "calculated value should be 1000", but it is rarely common to think "1000 should be my calculated value". Moreover, for example String assertEquals method contains 2 parameters, which of two are the expected value and current value?

III. Flexible notation in contrast to JUnit notation. For specifying that an element cannot be into a collection, in Junit assertFalse is used, and that's sounds strange using with a contains method of a list you can misunderstood exactly what are being test. Look Hamcrest expression, no possible error, we are asserting that "1+" not in validResults. Hamcrest has a module for treating collections expressions, like anyOf, isOneOf, hasItem, hasItems...

But wait, there is more, you can also build you own Hamcrest Matcher. A matcher is the responsible for validating if something is what expected. Hamcrest comes with a lot of built-in Matchers, but what's happen if we need one new matcher? Let's look an example:

Hamcrest does NOT comes with File matchers. We need to validate if after our business logic, a file is created in a directory.

- In Junit like expressions, would look something like:

final File createdFile = new File("test1");
assertTrue(createdFile.exists());


- In Hamcresst with built-in matchers:

final File createdFile = new File("test1");
assertThat(createdFile.exists(), is(true));


Maybe better than JUnit but expressiveness may be missing.

- What about that:

final File createdFile = new File("test1");
assertThat(createdFile, exists());


Better I think.

But a Matcher for asserting that, does not exists, so let's write one:

public class ExistsFileMatcher extends TypeSafeMatcher {

@Override
public void describeTo(final Description description) {
description.appendText("does not exists.");
}

@Override
public boolean matchesSafely(final File expectedFile) {
return expectedFile.exists();
}

@Factory
public static Matcher exists() {
return new ExistsFileMatcher();
}

}

One will agree that is so simple, only one method that validates the expression, other one that describes the error, and finally a factory.

And this matcher can be used in conjunction with other matchers. It is also valid that one:

final File createdFile = new File("test1");
assertThat(createdFile, not(exists()));


And that's Hamcrest, don't you think is a better way to express assertions rather than plain JUnit?

3 comentarios:

Maxime Nowak dijo...

Hi Alex,

I think that you should give a look at fest-assert : http://docs.codehaus.org/display/FEST/Fluent+Assertions+Module

I've used for a few years Hamcrest and now I am only using fest-assert.
Assertions are more fluents, and in some cases more easier to use.

An example :

List newEmployees = employees.hired(TODAY);
assertThat(newEmployees).hasSize(6)
.contains(frodo, sam);

Regards,

Maxime

Alex dijo...

Thanks for the comment I will take a look.

Meiqing Xu dijo...

oakley sunglasses
louis vuitton
hollister kids
adidas uk
yeezy boost
coach outlet
pandora jewelry outlet
gucci outlet
birkenstocks
true religion
20170123caiyan

Donate If You Can and Find Post Useful