Saturday, August 12, 2017

Developers, confess why you don't TDD

Dish me the dirt and give it to me straight. Don't hide anything. Just lay it out there: why don't you do TDD? TDD has been fighting for mainstream acceptance since the late nineties with the introduction of eXtreme Programming.  It's still not there yet. Today, at least everyone knows what the term TDD is but really so few actually know how to do it.
So I've put on a black shirt and twisted the collar on backwards, and I'm ready to take your confession.  Later, I'll cover your reasons, my dear developer, on Agile Thoughts podcast (http://agilenoir.biz/series/agile-thoughts/) where I'm doing a series on, brace yourself, "Why Devs don't TDD."

Like a good TDD priest, I'll keep the "actors" anonymous and discuss what I learn in an entertaining monologue.  So don't worry about your scandals and secrets.  What is your or your team's excuse?  What's the fear or problem? What's stopping you? 

And hey, if you are doing TDD, then why? What got you going?

Drop me the info either on the posting thread (Hacker News) or send me the "goods" via email: LancerKind@gmail.com

Thursday, May 25, 2017

Excelling at CucumberJVM GLOBAL Step Definitions

Cucumber is going global baby!  They've a vision that any and all definitions are available at the beck and call of any feature file.  Other BDD implementations allow static linking of feature file to a specific set of code of definitions.  Let's give the idea of global definitions a try with CucumberJVM (Java) and see what we can learn, cover tools and tricks to work with them, and look at how to design the definition code to be maintainable.  The code is on git hub along with tag points for "before" and "after" refactoring.

Feature files, Steps, Definitions, and Test Runners, oh my!

Feature files are text files containing the BDD (well really Gherkin) Steps such as Give, When, Then.  Definitions are built in programming languages and define what those steps mean.  Test Runners (such as JUnit, or cucumber command line) launch a program that looks for feature files, parses the feature file, and execute each Step by executing a Definition that matches the Step.  BDD Test frameworks usually allow some configuration of how to match a Step with a Definition.  Cucumber's vision is that all Definitions should be global and that the feature file should contain enough context to do this correctly.

Feature file for planning

This is the feature file used in planning.  It reads pretty well and gives a team a starting point for conversations on a point of sales feature for a pet store.
Buying a dog at a pet store such as Petco give you deals such as this.
(click pic to enlarge)
After planning with a number of such documented features, Once the Sprint started, during development of test automation, I realized I needed more context.  If the feature file alone was going to "drive" definition discovery, having descriptive columns wasn't going to give me enough differentiation across all steps in a global context.  example:
When purchasing a "selected accessory"
would generate a match for all other definitions with the words "When purchasing a," totally missing the important piece "selected accessory."
The Natural editor reporting multiple Definitions matching this Step.

Adjusting the feature file by pulling the descriptive columns "out" will allow us to work with global definitions.

How to know a Step has enough "closure?"

First off, we'll never be perfect as reality always brings new adventure. But you'll get closer faster by: reading each step alone, ignoring the context of the scenario title, feature file name, and feature file location.  This is how I realized that "When purchasing a" had too little context as the nice context of the column name wasn't going to help me.

So global definitions will make your feature files a little more wordy.  And you will be forced to make decisions in the future when you discover collisions.  Feature file editors like Natural will complain to you when you add one that has ambiguous definitions.

Test Automation Design

First off, let's get a feedback loop working.  (Code is on GitHub.)  Put the feature file into source control, add a test runner (or if you got the cucumber plugin working in eclipse, that will work too), and execute your test.  Observe that the feature file is executed but the scenarios are skipped as there are no definitions.  Also the console will give you stub code for the methods.

Organize feature files in a sensible hierarchy

JUnit test runner

JUnit test case which hands off to Cucumber
Natural gives feedback that definitions are missing
(If you add definitions, sometimes the feature file needs to
be reopened to force Natural to repairs and check.)
Global definitions change how automation is designed and built.  When using BDD tools that allow the developer to control linking Steps to Definitions, you'd typically see a one to one mapping of feature file to the java file containing the class of definitions:
com/features/purchasing/BuyDog.feature
com/features/purchasing/BuyDogStepDef.java
com/feature/pageobjects/....   
With Cucumber, you're encouraged to build classes in this manner:
com/features/purchasting/BuyDog.feature
com/features/definitions/GivenBuysDog.java
com/features/definitions/WhenBoughtSelectedAccessory.java
com/features/definitions/ThenDiscount.java
com/feature/pageobjects/....  
Although this explosion of smaller objects isn't necessary a bad thing, it leaves us with a problem:  "When" at line 8 needs to communicate with the "Then" at line 9, so these smaller objects need a way to communicate with each other.  A Singleton pattern could do this but puts more burden on the programmer, as now lifecycle management needs to be done to maintain isolation between tests (so that running one scenario doesn't cause a side affect with another scenario due to mismanaged state in a Singleton).  A better alternative is to work with Cucumber's lifecycle for doing this via dependency injection.

Working inside a World

The World lifecycle pattern is simple: the state to be shared between Definitions is stored in the World, and the world is created at the start of executing a scenario and then destroyed upon completion of the scenario.  Upon execution of a new scenario, a new World is created again, and so on.  Although the World pattern is heavily emphasized in Cucumber.JS, it's not so explicit for CucumberJVM.  Cucumber manages the World lifecycle automatically if you use Dependency Injection.  PicoContainer (built by the authors of Cucumber) is a simple and lite weight framework that gets the job done via constructor injection.

Here's how

Add picocontainer to your build dependencies (Because I found PicoContainer.org hard to work with, I used Maven.org to search for the latest versions of "cucumber-picocontainer" and "picocontainer."):
Add two jars to activate World lifecycle and Dependency Injection
Take a look at your three definitions and create a new class for passing information.
Three Step Definitions
Since in this case it's about a shopping cart of items, lets go with that.
For now put the object in the same package as its steps in the top level package for definitions.  Later we'll reorganize but for now keep writing code because it will be easier to re-organize after more of the design has emerged.  Since PicoContainer uses constructor injection, add Constructors for the data injection.
Constructor Injection
(Click pic for larger resolution)
This is all the "structure" code needed for PicoContainer and Cucumber.  When Cucumber executes a feature file with these steps, and it matches to these definitions, it will use PicoContainer to find and inject the dependencies when it constructs these classes, and these dependencies will be inserted in the World during Scenario execution.

Here are the Given, When, Then definitions using the dependency:


 Execute the test runner and you'll see this is enough for the first scenario outline.


To illustrate the World is being destroyed, a short experiment such as injecting a counter to count how many times the Given is called will make this clear.

Counter is always one because it's replaced each time the Scenario is run
(Click to see full size pic.)
Although Counter is always incremented in the definition for Given, and checked in the definition for the Then, it is always set to 1 because each row of a scenario outline gets it's own World.

Ramifications of Global Definitions on Design

A good design does at least these two things well (in this order) that allow a program to respond to change:
1) communicates intent in an understandable way,  and
2) is maintainable.
Another 50 pages could be written about other important characteristics--the book Clean Code is a good reference--but let's keep it to the point: we don't program in binary because it's difficult to understand intent and if we wrote in binary anyhow, eventually you'll be hating life when you have to respond to new requirements.

Global definitions mean our feature files could have a relationship with any definition (Java class with a @Given, @When, @Then.  So organize the features files in a way that makes the feature files an index into your product's features.  Feature files will be the index into your definitions (Java code) as well.  To organize the java code so it communicates intent and is maintainable, use the principle of "keeping things that work together next to each other."  Said another way, keep definitions grouped with the things your injecting into them.  This is a big departure from BDD frameworks that don't do global definitions, where usually the feature files and definitions are grouped together in "src/java/com/feature/purchase/buydog."  With global definitions, doing so would actually misinform.  With global definitions, it'd be better to drop everything in one namespace.  But lets try something better than that.

For example, organize feature files thusly (there may not be an advantage to having feature files children of src/java directory, but I did this out of habit):
src/java/com/features/purchase/BuyDog.feature
src/java/com/features/purchase/BuyCat.feature
src/java/com/features/purchase/BuyFish.feature
src/java/com/features/returns/ReturnFishTank.feature
src/java/com/features/returns/ReturnDog.feature

For Java code, I looked at each set of definitions and their collaborators and tried to group them in a sensible way:
Then later, when I added automation for the few selected accessories a few are not


I had to decide if I wanted to collaborate between the When and Then with the shopping cart, I needed to drop them in the same "shopping" namespace as the previous scenario.  The fact that I'm using the same Given definition, then that reinforces that decision.  This all makes sense since they are all about the same thing.  But get used to the idea that just because steps are in the same feature file, their definitions could be anywhere.

Times goes on keep the stair rails polished

Since feature files are a reflection of a product's features, BDD test automation needs to respond to three kinds of changes:
  • new behaviors/features, 
  • adjusting existing behaviors/features, and 
  • adjust how existing behavior/feature operates.

New behaviors versus adjusting existing behaviors

Organize feature files in a sensible hierarchy with good feature file names so it's easily browsable and searchable in order to answer the question, "is this new idea the PO has a new behavior or a change in an existing behavior?"
src/java/com/features/purchase/BuyDog.feature
src/java/com/features/purchase/BuyCat.feature
src/java/com/features/purchase/BuyFish.feature
src/java/com/features/returns/ReturnFishTank.feature
src/java/com/features/returns/ReturnDog.feature 
...
(It'll be hard to organize features without knowing the business you're building behaviors for.  Go find someone to help/interview about that as this knowledge typically isn't in the IT part of the organization.)

The business want's to collect customer contact info so they can send them offers via physical mail or email.  To do that, they make this offer to the customer at time of checkout by offer VIP cards that give an additional 5% discount on purchases to collect your contact info and send you more offers. 
If it's known that there will be ten more VIP card behaviors, better to make a directory just for different VIP features.  But if all we know at the time is that there is just this one feature, then we can just add the behavior into an existing feature file as shown (we can always move the feature files around later).
Adding another scenario outline (highlighted) to BuyDog
The global definitions related to these steps need to be updated to pass information about the VIP card status (the definitions for the Given and Then).  Because the definitions are global, finding the impacted definitions should be driven from the feature file.  If you've a good feature file editor like Natural, you can open those steps so you can implement a good way to inject (via PicoContainer) an object to pass along VIP card status.  If you haven't a good editor, then use your IDE to search for the step, filtering by .java file.  If you use IntelliJ, it has built in support for Gherkin so that you can put the cursor on a feature files step, then with a CTRL/CMB-B, get to the definition defined by your Java code.  If you have nothing but vanilla Eclipse (no Natural plugin), here is how to work with search:




Answering the question, "what feature files use this definition?" is a bit harder in that you need to avoid the regex expressions.  I'm not aware of any tools that help.


Adjusting only implementation
In this case, the behavior has been implemented but, darn it, the implementation just seems lacking or is in need of an update.  Assumedly the PO knows it's an update of an existing implementation by browsing through the feature documentation (maybe it's been turned into a GitBook).  The team brings the story in with a reference to the existing feature file and a simple bullet points on how to change the implementation.  During the sprint, the developers start at the feature file and from there open the definitions, read the Java code, and then make changes to the definition to get the test failing because the definition has been updated to the new implementation.  With the automation complete, the developers build the functionality (assumedly using TDD so they have micro tests which keep test automation in a sleek and pointy pyramid shape.)

Closing Thoughts

With support from a feature file editor that will escort you to the definitions, World lifecycle management enabled via dependency injection, and the fact that Cucumber is maintained by developers with significant control of the direction and vision of the company (Aslak Helles√ły,  Joseph Wilk, Matt Wynne,Gregory Hnatiuk, and Mike Sassak) I'd say give global definitions a try.  It's easy to dismiss trying something like this out of hand.  In fact some have mentioned how they've tried global definitions and failed, (see References section, "Global scoping is Evil").  In that case they were doing BDD incorrectly (not doing *B* DD at all in fact) as shown in the below, complaining about "click the search button."
Implementation details about UI aren't behavioral
Building "un"behavioral tests is a common early adopter's mistake which can happen to even experienced people who haven't stepped out of the box.  Games like the Behavioral or Not? teach how to build feature files at the correct level.  Building tests in the way the author of the above wanted to wasn't maintainable so this effort was in bad shape with or without global definitions.  Global definitions forced them to fail faster which was a good thing as they would give up rather than build a bunch of automation that's expensive to maintain.  This is likely one of the reasons Cucumber removed the ability to not use global definitions.  If you're still unsatisfied, use some strategies to teach Cucumber about boundaries, use a different BDD framework such as JBehave, or change Cucumber (it's open source) yourself to meet your needs.

References

Lance's example code for this article on GitHub
picocontainer-for-singleton-di
how-to-pass-variable-values-between-steps-in-cucumber-java
Cucumber BDD environment installation
Global Definitions are EVIL

Troubleshooting

JUnit green bar stops rendering and tests not working

Click in the Test Selection window and look for a stack trace in the Failure Trace pane.  In cases like this, something has happened before JUnit execution has even started.  You'll need to correct the problem exposed in the Failure Trace.

Arity Problem

Failure Trace shows Arity problem
Fiddling with feature steps that already have definitions may result in the above when there is a mismatch between the number of parameters Cucumber is trying to pass from the step in the feature file into the definition.  Check the definition's parameter list and the feature file to see which needs to be straightened out.

Monday, May 1, 2017

Teaching Cucumber about Boundaries

Developers are trained to avoid using global anything in programs because you're making big commitments to the uncertain future.  Behavior Driven Development (BDD) demands teams and their source of requirements to decide what words mean, and then write test automation code that enforces the meaning.  In this way BDD encourages the definition of words to be used globally in a specific way in requirements.  The problem with Cumber (and all? implementations of Gherkin) is that the only information passed from the feature file to the automation framework is the the usual Gherkin keywords: Given, When, and Then, which isn't the whole picture.  Developers, since they can read the whole feature file, can teach the automation to do the right thing by linking to specific steps definitions designed with the whole situation in mind.  The BDD framework Cucumber, in particular, doesn't make it simple to control linking feature files to specific test automation (known as step definitions) because it's optimized for a flat global namespace between a feature file and the many step definitions, but there are some boundary controls.  Let's look at different levels of boundaries that can be created between your features files with Cucumber-JVM.

The Problem

Take a look at the below two feature files (click for high-res viewing):
Feature File
To implement test automation for these two feature files, a Java programmer (in the case of Cucumber-JVM) must write java code that drives their product to prove it works as the customer expects.  The problem comes up with "Then signoff" because a single Java method cannot figure out how to handle this case.  Although "signoff" is used in both features, it means two different things.  It's a pity that although the feature files have quite a lot of context (Feature title, user story, scenario title, directory location) which actually makes it clear what is meant by "signoff," none of that is available to communicate context when doing test automation in any of the Gherkin BDD frameworks.  The above two features are in two domains different domains: the domain of package delivery and the domain of multi-user systems.  One strategy is to recast the sentence "Then signoff" in one or both of those feature files so this overlap doesn't exist, and this is the first thing to try when faced with this.  In cases where such a collision is using words that are a "fixed part of the domain language" then we may want to *not* have a global namespaces and instead create a boundary (AKA a bounded context in Domain Driven Design terms).

Conceptually global step functions look like this (click pic for high resolution image):
Global Scope Step Definitions in a global 'dictionary'
Where you'll have a lot of Java steps definitions designed around each gherkin statement.  There isn't a direct relationship between a specific feature file and a specific steps definition.  Here the idea is to have many re-usable steps definitions (and an automation library that's used across all the steps definitions).


But perhaps, you want this for fine grain control and let the developer control all aspects of how each step in the feature file is automated (click pic for high resolution image):
Each feature file has it's own namespace for steps definitions
Here, each feature file gets one (or more) java classes to handle the scenarios within the feature file.  The relationship between the steps and the feature file are intimate.  The idea here is to have a very simple steps definition for a specific .feature file, and to push as much code as possible into the automation library so it can be re-used across all the steps definitions.

You can get to this extreme with some easy to do but additional steps.

Global Scope

This one is easiest to get started with as Cucumber is geared to make this easy.  Your test automation project should have package arranged like:

test.pageobjects
test.features
test.features.major_feature_one
test.features.major_feature_one.subfeature
test.features.major_feature_two
...

Create a JUnit execution class at the top of your test automation project like shown.
How everything works is that when launching the JUnit test case, it hands off to Cucumber via the @RunWith, which associates all the subpackage from that point as the namespace to use for matching step definitions.  So by putting the JUnit Test class at test.features makes all of our feature files from test.features and downward, match to any of the step definitions declared from this point on down.  (BTW, there are tools such as Natural that help in editing feature files and finding which step definition is active.)

Here's the big news: Nothing is stopping us from having multiple JUnit Test classes in different peer packages, effectively creating boundaries for how step functions are picked up by feature files.

Package Scope

By putting a Cucumberized JUnit Test case at the top of specific packages, we create separate bounded contexts, a term used by the practice Domain Driven Design, which basically sums up to: put the features and steps for the package delivery in one Java namespace and the features and steps for multiuser in another Java namespace, and then in each package, setup a Cucumberized JUnit Test case.  In this way, boundaries between these two different domains are made.

It looks like this:


Package organization
test.features.packagedeliver contains one Cucumberized JUnit Test case, many steps definitions, and many feature files.  test.features.processcontrol contains one Cucumberized JUnit Test case, many steps definitions, and many feature files.

Thusly its possible to have a "Then signoff" defined in a steps definition in the processcontrol context and a different definition for "Then signoff" by a steps definition in the packagedelivery context.  If another "Then signoff" steps definition is added to say, test.features.processcontrol.increase_system_load, Cucumber will put the brakes on and complain that "Then signoff" is ambiguous as there are multiple definitions in its bounded context.

But what if that isn't enough?  Can we make every feature file have its own context?  You bet.

Feature File Scope

If you need to do this, it's a bit of drudge work but it's not complex: for every feature file you'll need to add a Cucumberized JUnit test case, and due to a lovely quirk of Cucumber, drop that feature file's step definitions in their own package. #annoying

Conceptually that looks like this:
Literally, it looks like this (click image to see what's going on):

Two feature files in the test.features.processcontrol package want different step definitions for "Then signoff"

Now each Cucumberized JUnit test case defines the mapping from a specific feature file and a package to where to load its step definitions.  Because this strategy will end up producing a bunch of different JUnit test cases, you'll want to add a JUnit test suite so you can easily execute all your feature tests with one click.

Conclusions

You've got the tools to do whatever you want with Cucumber.  Treating every feature file as having its own scope is the ultimate of control but do you really need that?  The OCD control freak inside does want that and if so, better to find another framework to support that then Cucumber.  Defining boundaries using packages will keep the DDD people happy and would work in a pinch when you need it.  Cucumber is courageous in pushing people to build global dictionaries.  I've only heard of great drama coming out of such striving though people have successfully done it.  It seems unfair to having our language in feature files be global context (easy to do as we are humans) and then forcing the automation (a computer program) to discover the context when Gherkin doesn't passalong all the context from the feature files.

I'm happy to hear from you if you've a story to share: Twitter:@LancerKind, LancerKind@gmail.com.

References

JUnit 4 Test Suites

Tuesday, May 24, 2016

Exceptional Exception Testing with JUnit 4.11 Rules and Java 8/JUnit5

Zipporah taking exception to poor 'ol Babbage


You've got something that takes exception to something else and now you want to automate a test to confirm it correctly throws per your specification:




 public class ProblemCauser {
    public void throwsException() {
        throw new IllegalArgumentException("Negative");
    }
}  
One way is the below. But can you see a problem?
import static org.junit.Assert.*;
import org.junit.Test;
public class RulesAndExceptionTest { 
 
    @Test(expected=IllegalArgumentException.class)
    public void canOnlyCheckTypeButNotMessage()
    {
        ProblemCauser problem = new ProblemCauser();
        problem.throwsException();       
    }
}
How do you know the exception message has been set to "Negative?" In the past, that left you with the following strategy:
    @Test
    public void theOldWayToTestExceptionMessageAndType() {
        try {
            ProblemCauser problem = new ProblemCauser();
            problem.throwsException();
            fail("didn't get expected exception");
        } catch (IllegalArgumentException expected) {
            assertEquals("Negative", expected.getMessage());
        }

    }
This does the job. Good work! You can actually fully test drive exception handling with this strategy.  The drawback is this is a lot of code to express a simple check. Even worse, many people forget to include the fail() call, which means if an exception doesn't happen, the test would pass.  This would be an incorrect test case. A better strategy is to use Junit 4.11's Rules package:
import static org.junit.Assert.*;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class RulesAndExceptionTest {
    @Rule
    public ExpectedException
exceptionPolicy = ExpectedException.none();  // Set the default expectation.
    @Test
    public void theNewWayToTestExceptionAndType() {
        exceptionPolicy.expect(IllegalArgumentException.class);
        exceptionPolicy.expectMessage("Negative");


        ProblemCauser problem = new ProblemCauser();
        problem.throwsException();
    }
}
 This is equivalent but uses less code. How does it work?

Exceptional with @Rules

 org.junit.Rule is an annotation that can be applied to a field or method. When JUnit executes the test class, it hands control to the Rule and decides how to execute Before, Test, and After, allowing the it to manage whatever it is supposed to manage. In the case of ExpectedException, allowing it to execute the @Test method and handle any exception thrown out to see if it's expected.

You can have multiple Rules in a test class doing various things. Here are other org.junit.rules.*(http://junit.org/junit4/javadoc/latest/org/junit/rules/package-summary.html):
Click image to zoom.
 Using JUnit's Rules, you can clean up exception handling code to one to three lines of code (one for the test class field, then one where you expect to get an exception) making it more readable and less error prone than using a try{...fail();}catch(Exception ex) { assertEquals(...);} pattern. More functionality with less code. That's exceptional!

Even MORE Exceptional with Java 8 and JUnit 5

JUnit 5 alpha was released in 2016 and it was designed to use Java 8 language features. assertThrows() tests if the exception type was correct. expectThrows() does the same AND returns the exception type so you can examine it further.
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import org.junit.gen5.api.Assertions;
import org.junit.gen5.api.Test;
import org.junit.gen5.junit4.runner.JUnit5;
import org.junit.runner.RunWith;

@RunWith(JUnit5.class)
public class ExceptionTestingTest {
    @Test
    public void throwsExceptionWhenPopped() {
        ProblemCauser problem = new ProblemCauser();
        Throwable exception = Assertions.expectThrows(IllegalAccessException.class, () -> problem.throwsException());
        assertThat(exception.getMessage(), startsWith("Error:"));
    }
}
Java 8 and JUnit5 make exception testing even more exceptional. Java 8 makes it possible to pass function pointers. So now the function pointer to throwsException is passed into expectThrows. And because expect throws returns the Throwable, it's possible to check it's state. Notice the use of hamcrest's assertThat as JUnit5 doesn't have one. 
To get the Alpha 5.0 release to work with Eclipse's JUnit 4 plugin per: http://junit.org/junit5/docs/current/user-guide/#using-junit-4-to-run-junit-5-tests, I had to add the following dependencies to my build path (see Referenced Libraries). 
Notice JUnit 4 on the end.  This is for the @RunWith. If you have problems, scroll down to this article's Troubleshooting section. JUnit 5 and Open Test are available at Maven.org.

Other Solutions

Outside of JUnit 5, here are some other solutions but they seem "exceptional" as they require more code and dependencies than using JUnit4 Rules and the code doesn't seem more readable. Here are some articles:

References

http://junit.org/junit4/javadoc/latest/org/junit/Rule.html
http://junit.org/junit5/docs/current/user-guide/#migrating-from-junit4
http://junit.org/junit5/docs/current/user-guide/#using-junit-4-to-run-junit-5-tests
JUnit 5 API docs on assertThrows and expectThrows:  

Troubleshooting

JUnit5 with Eclipse JUnit 4 plugin test runner:
  •  ClassNotFound issue with DiscoveryFilter 
    • Solution: add junit-engine-api-5.0.0-ALPHA.jar to the build path.
  •  TestRunner executes but doesn't show any test being run. 
    • In the console, you see the following: org.junit.gen5.launcher.main.ServiceLoaderTestEngineRegistry loadTestEngines
      INFO: Discovered TestEngines with IDs [junit5]
      java.lang.NoClassDefFoundError: org/opentest4j/TestAbortedException
          at org.junit.gen5.engine.support.hierarchical.HierarchicalTestExecutor.(HierarchicalTestExecutor.java:37)
    • Solution: go to Maven repo and add OpenTest4J jar to the build path.
  

Thursday, May 5, 2016

Asserting like a Hipster

You know the type. For the past year they've been using the latest new programming language that you just discovered yesterday. They have the latest mobile device with the beta OS, and their laptop is loaded out with more experimental tools than a mad scientist's closet. Hipsters! Every team should have one because they keep us pushing for the next "something better." (Image source: Damn it's hard (and expensive) to be an Alabama hipster.)

Years ago new Java language features along with Hamcrest's matcher library created some changes in JUnit 4.4. Although experienced hands are used to reading the assertEquals(expected, butGot) pattern, if you free yourself from tradition, I think you'll agree that combining Hamcrest with Junit makes tests more readable. Click on the below thumbnail and compare the readability of the test on your left versus right. Although you may be used to reading assertEquals(...), which one would your mother find most understandable?
Tap to zoom
Not only does assertThat(...) read better, it has more advanced matching capabilities so you can do in one line what takes several lines of assertEquals(...) or assertTrue(...). (Source: https://github.com/junit-team/junit4/wiki/Assertions)
tap to zoom
And the error messages are readable without having to write your own (See assertTrue versus assertThat, for example.):

tap to zoom

Setting it up

The setup is difficult which is probably why not many use the more expressive assertThat:
  1. The eclipse JUnit plugin ships with a paired down version of Hamcrest which means although you get good API help via examples on the internet, the version with Eclipse sometimes can't do it or the packages are different (for example, can't do assertThat on a double because the paired down Hamcrest lacks the Matchers for doubles.
  2. "Out of the box" Eclipse's content assist (aka: command complete, intelli-sense) feature isn't any help for discovering the Hamcrest Matchers.
  3. assertThat isn't necessary for doing TDD. TDD adopted alone is hard enough so mixing the "doing TDD" with using assertThat means adding yet another barrier to coaching developers to do TDD, so it's skipped as a future refinement to learn.
 To use assertThat, the "hipster tax" must be paid. Let's get started.

Install latest Hamcrest library

 Go get java-hamcrest jar and add it to your project as an external jar library, and add it ahead of JUnit 4 in the build path (otherwise it'll use the "partial" hamcrest library that was added into the JUnit 4 plugin.
The dependencies for using Junit assertThat with Hamcrest Matchers is satisfied. Create a test class and copy paste the below code into your project, and run the test to see if your environment is OK.  The second test won't even compile if you're trying get by with the Hamcrest that came with Eclipse's JUnit plugin.
package foo;
import static org.hamcrest.CoreMatchers.is;
//import static org.hamcrest.Matchers.closeTo;
import static org.junit.Assert.*;
import org.junit.Test;

public class AssertThatTest {
    @Test
    public void assertThat_worksWithHamcrest() {
        int five = 5;
        assertThat(five, is(5));
    }
/*    @Test
    public void assertThat_accessToModernHamcrest() {
        Double five = 5.005d;
        assertThat(five, is(closeTo(5d, .005d)));
    }
    */   
}
You can get started testing, but to make working with Hamcrest enjoyable we need to configure Eclipse.

Configuring Content Assist

Without Content Assist support, using Hamcrest Matchers becomes a productivity suck. Until fixing this, the only recourse is Google or hunting via typing full package names to figuring out what matcher to use.
Out of the box Ecilpse is zero help finding matchers to use with assertThat
Go into Eclipse's Preferences and configure "Favorites" to clue in Content Assist for org.hamcrest.CoreMatchers and org.hamcrest.Matchers.





 Afterwards, Eclipse will give you a helping hand, and at this point the hipster tax has largely been paid (anyone know anyone at Eclipse Foundation who is positioned to fix this so it works out of the box?):
Think "is" for comparing a single something. Think "has" when comparing an array or collection to a single or collection of somethings

You'll be able to do more with less code, and that's a beautiful thing. The following is a taste of the Matcher menu: collections, string comparisons, iteratable objects, time comparison.




Done

After this, you can assertThat(you, is(hipster_cool)). Better get started though. Because soon everyone will be doing it and assertThat won't be hip any longer 'cause it'll be mainstream.

Now get 'er done hipster!  
(Image source: http://hipster-lifestyle.com/. R U hip enough to even read that site?)

Troubleshooting

If you don't change the project dependency order so that java-hamcrest is before JUnit 4, you'll get the following exception during test execution because of a compatibility issue when trying to use Eclipse's JUnit plugin's older/partial Hamcrest:
Select to zoom.

References

http://edgibbs.com/junit-4-with-hamcrest/

http://stackoverflow.com/questions/2922879/best-way-to-unit-test-collection 

http://stackoverflow.com/questions/21624592/hamcrest-compare-collections