SlideShare a Scribd company logo
Hamcrest Matchers
assertThat(audience, is(payingAttention()));




     Writing and using them for
 assertions, mocking and behavioral
             verification
What is Hamcrest?
According to the project homepage,
  [Hamcrest] provides a library of matcher objects (also known
  as constraints or predicates) allowing 'match' rules to be
  defined declaratively, to be used in other frameworks. Typical
  scenarios include testing frameworks, mocking libraries and
  UI validation rules.

  Hamcrest is not a testing library: it just happens that
  matchers are very useful for testing.
Typical usage example
                             Actual value
assertThat(
     someString,
     is(equalTo(someOtherString))
);
                                      Expectation on the
                                     value, represented as
                                          a Matcher
Wait – but what’s wrong with
           assertEquals?
assertEquals(someString, someOtherString)
         This looks just as good, doesn’t it?

assertEquals(
     cat.getName(),
     otherCat.getName())

         Not so bad, either
However,
             What about collections?

assertEquals(someKitten,
     cat.getKittens().iterator().next())

 This works if our kitten is the first element in the
 collection, but what about asserting that the kitten
 exists anywhere in the collection?
Well, we can do this:
boolean found = false;

for (Kitten kitten : cat.getKittens()) {
      if (kitten.equals(someKitten)) found = true;
}

assertTrue(found);
But don’t you prefer this?
                            Iterable<Kitten>
assertThat(
     cat.getKittens(),
     hasItem(someKitten))

                                      Matcher on
                                 Iterable<Kitten> that
                              accepts a Matcher<Kitten>
OK, so how does this work?
Basic Matchers
A Matcher is initialized with the expected
values, which are compared against the
actual object we’re matching against when
invoking the matcher.
IsEqual Matcher
class IsEqual<T> extends BaseMatcher<T> {
   private final Object object; // c’tor omitted for readability

    public boolean matches(Object arg) {
      return object.equals(arg);
    }
}
StringEndsWith Matcher
class StringEndsWith <T> extends BaseMatcher<T> {
   private final String suffix; // c’tor omitted for readability

    public boolean matches(String s) {
      return s.endsWith(suffix);
    }
}
Using while stubbing mocks
Mockito in one slide
CatShop catShop = mock(CatShop.class);
when(catShop.purchase(somePurchaseRequest
).thenReturn(someCat)             Creating the mock



... do some work                      Stubbing the mock




verify(catShop)                Behavior verification


 .purchase(expectedPurchaseRequest)
Without Hamcrest
CatPurchase catPurchase = new CatPurchase();
catPurchase.setBreed(“Brittish”);

when(catShop.purchase(catPurchase))
).thenReturn(somePreviouslyStubbedCat)
However, this will force us to set all other fields of the
CatPurchase class, since Mockito will perform an exact match
comparison between our instance and the actual one
Of course, you could do this:
when(
      catShop.purchase(
           any(CatPurchaseDTO.class))
).thenReturn(somePreviouslyStubbedCat)

This works, but lacks the benefit of asserting that our
operation is only valid for the expected input
The solution: use argThat()
                               Mockito helper that creates
                               an argument matcher from
when(                             a Hamcrest matcher

      catShop.purchase(argThat(
           hasPropertyWithValue(
                “breed”,
                startsWith(“Brittish”))))
).thenReturn(somePreviouslyStubbedCat)
                                 Hamcrest matcher that
                                   accepts a Java Bean
                                  property name and a
                                 nested value matcher
Using for behavioral verification
CatDao catDao = mock(CatDao.class);
CatStore catStore = new CatStore (catDao);with a Catcall to
                                     Verify that there was a
                                CatDao.update()               instance,
catStore.saveOrUpdate(existingCat); the ‘name’ property is
                                   for which
                                “felix” and the ‘kittens’ property is an
verify(catDao).update(argThat( Iterable containing two kittens,
                                          kitten1 and kitten2
       allOf(
              hasPropertyWithValue(“name”, “felix”),
              hasPropertyWithValue(“kittens”,
                    hasItems(kitten1, kitten2)))));
Writing custom matchers
Writing your own matchers
In the previous examples, we used the
hasPropertyWithValue() matcher, which, while
allowing for fluent assertions or stubbing, has
the disadvantage of not being type-safe.

This is where writing custom matchers becomes
useful (or, as some would say, necessary).
The Matcher<T> hierarchy
abstract class TypeSafeMatcher<T> extends BaseMatcher<T> {
  boolean matchesSafely(T item);
}

interface Matcher<T> extends SelfDescribing {
   boolean matches(Object item);
}

interface SelfDescribing {
   void describeTo(Description description);
}
Dissecting some Wix matchers
class HostMatcher extends TypeSafeMatcher<WixUrl> {
   private final Matcher<String> host; // c’tor omitted for readability

  public boolean matchesSafely(WixUrl url) {
    return host.matches(url.host);                                Nested matcher that
  }                                                              will be replayed on the
                                                                 Actual value being
                                                                       actual value
                                                                  matched against
  public void describeTo(Description description) {
    description.appendText("Host that matches ").appendValue(host); we write a
                                                               Here
  }                                                         readable description of
                                                              our expected value

  public static HostMatcher hasHost(Matcher<String> host)A utility factory method for
                                                         {
    return new HostMatcher(host);                           fluently creating this
  }                                                       matcher. Not mandatory
}                                                           but very convenient.
Using our matcher
WixUrl url =
new WixUrl(“http://www.wix.com/some/path”);

assertThat(url, hasHost(is(“www.wix.com”)));   ✔
assertThat(url, hasHost(endsWith(“wix.com”))); ✔
assertThat(url, hasHost(is(“google.com”)));    ✗
                           java.lang.AssertionError:
                Expected: Host that matches <is ”google.com">
                    got: <http://www.wix.com/some/path>
Another URL matcher
class WixUrlParamMatcher extends TypeSafeMatcher<WixUrl> {
  private final Matcher<String> name; // c’tor omitted for readability
                                        url.params is a Map<String, String>, so
  private final Matcher<String> value;
                                         we create a matcher for a map entry
                                         around our name and value matchers
    public boolean matchesSafely(WixUrl url) { replay it against the actual value
                                         and
        return hasEntry(name, value).matches(url.params);
    }

    public void describeTo(Description description) {
      description
           .appendText("Param with name ").appendValue(name)
           .appendText(" and value ").appendValue(value);
    }
}
Using the two matchers together
String s = “www.wix.com?p=v1&p=v2&p3=v3”;
WixUrl url = new WixUrl(s);

assertThat(url, allOf(
     hasHost(is(“www.wix.com”)),
     hasParam(is(“p”), anyOf(is(“v1”), is(“v2”))),
     hasParam(is(“p3”), startsWith(“v”))));
But wait – my URL is a String!
Sometimes you’ll have matchers that accept a specific
type, such as WixUrl or XML Document. For this
purpose, use a wrapping matcher that performs the
conversion for you:
class StringAsUrlMatcher extends TypeSafeMatcher<String> {
  private final Matcher<WixUrl> urlMatcher;
  public boolean matchesSafely(String urlString) {
     return matcher.matches(new WixUrl(urlString));
  }
  public void describeTo(Description description) {
     description.appendText("Url that matches ")
          .appendDescriptionOf(urlMatcher);
  }
}
Ad-Hoc matchers for readable
           tests
Consider the following class

class Proxy {
   private final HttpClient httpClient;
   private String targetUrl;

    public String handle (String path) {
       httpClient.execute(// some HttpGet);
    }
}
The HttpClient interface
public HttpResponse execute(HttpGet get);

Our class under test is expected to replace the domain
in path with targetUrl, thus serving as an HTTP Proxy.

We would like to stub and verify the HttpGet parameter
to make sure it builds the proxy URL properly.
My test looks something like this
HttpClient client = mock(HttpClient.class);
String url = “http://www.example.com/”;
{…} handler = new Proxy(client, url);
when(client.execute({www.a.com/path}))
       .thenReturn(someResponse);

handler.handle(“www.a.com/path”);

verify(client).execute({www.example.com/path});
The solution
Matcher<HttpGet> HttpGet(final Matcher<String> urlMatcher) {
 return new TypeSafeMatcher<HttpGet>() {
   public boolean matchesSafely(HttpGet httpGet) {
     return urlMatcher.matches(httpGet.getURI().toString()));
   }

         public void describeTo(Description description) {
           description.appendText("HttpGet with url ")
             .appendDescriptionOf(urlMatcher);
         }
    };
}
Usage of the HttpGet matcher
when(handler.execute(argThat(
      is(HttpGet(startsWith(“http://www.a.com”))))))
  .thenReturn(response);

handler.handle(“http://www.a.com/some/path”);

verify(client).execute(argThat(is(HttpGet(
       is(“http://www.example.com/some/path”)))));
The plot thickens
Moments after triumphantly running the test I
realized that in addition to verifying that the
request went to the appropriate URL, I had to
verify that some – but not all – HTTP headers
were copied to the proxy request and some new
ones were added to it.
Ad-hoc matchers to the rescue
1) Add the following parameter to the HttpGet
   method:
 final Matcher<Header[]> headersMatcher


2) Change the matchesSafetly() method:
 public boolean matchesSafely(HttpGet httpGet) {
   return urlMatcher.matches(httpGet.getURI().toString())
     && headersMatcher.matches(httpGet.getAllHeaders());
 }
Ad-hoc matchers to the rescue
3) Write a matcher for the Header class:
Matcher<Header> Header(
  final Matcher<String> name, final Matcher<String> value) {
  return new TypeSafeMatcher<Header>() {
     public boolean matchesSafely(Header header) {
        return name.matches(header.getName())
               && value.matches(header.getValue());
     }
  }
}
Putting it all together
verify(client).execute(argThat(is(HttpGet( that the X-Wix-Base-Uri header
                                     Asserts
                                     contains the expected value (using the
  is({URL matcher omitted for readability}),
                                     WixUrl matchers we’ve seen before).
  allOf(
    hasItemInArray(
      Header(
       is("X-Wix-Base-Uri"),
                                      Asserts that there’s no header by
       isUrlThat(                     the name of X-Seen-By, no matter
                                      what value it has
          hasHost(“www.wix.com”), hasPath(myPath)))),
    not(hasItemInArray(
      Header(is("X-Seen-By"), any(String.class))))
)))));
Questions?




             shaiy@wix.com
http://il.linkedin.com/in/electricmonk
     http://twitter.com/shaiyallin

More Related Content

What's hot

Sqlite
SqliteSqlite
Sqlite
Kumar
 
Selenium WebDriver
Selenium WebDriverSelenium WebDriver
Selenium WebDriver
Yuriy Bezgachnyuk
 
Testing android apps with espresso
Testing android apps with espressoTesting android apps with espresso
Testing android apps with espresso
Édipo Souza
 
Unit Testing And Mocking
Unit Testing And MockingUnit Testing And Mocking
Unit Testing And Mocking
Joe Wilson
 
JUnit Presentation
JUnit PresentationJUnit Presentation
JUnit Presentation
priya_trivedi
 
MVVM ( Model View ViewModel )
MVVM ( Model View ViewModel )MVVM ( Model View ViewModel )
MVVM ( Model View ViewModel )
Ahmed Emad
 
Swift UI - Declarative Programming [Pramati Technologies]
Swift UI - Declarative Programming [Pramati Technologies]Swift UI - Declarative Programming [Pramati Technologies]
Swift UI - Declarative Programming [Pramati Technologies]
Pramati Technologies
 
Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass Slides
Nir Kaufman
 
Spring Framework - Core
Spring Framework - CoreSpring Framework - Core
Spring Framework - Core
Dzmitry Naskou
 
TestNG Framework
TestNG Framework TestNG Framework
TestNG Framework
Levon Apreyan
 
Core java concepts
Core java  conceptsCore java  concepts
Core java concepts
Ram132
 
Automation - web testing with selenium
Automation - web testing with seleniumAutomation - web testing with selenium
Automation - web testing with selenium
Tzirla Rozental
 
Unit Testing in Java
Unit Testing in JavaUnit Testing in Java
Unit Testing in Java
Ahmed M. Gomaa
 
Spring Boot
Spring BootSpring Boot
Spring Boot
Jiayun Zhou
 
How to go about testing in React?
How to go about testing in React? How to go about testing in React?
How to go about testing in React?
Lisa Gagarina
 
Selenium
SeleniumSelenium
Selenium
Adam Goucher
 
Unit testing with JUnit
Unit testing with JUnitUnit testing with JUnit
Unit testing with JUnit
Pokpitch Patcharadamrongkul
 
Selenium WebDriver training
Selenium WebDriver trainingSelenium WebDriver training
Selenium WebDriver training
Vijay Krishnan Ramaswamy
 
Jsf presentation
Jsf presentationJsf presentation
Jsf presentation
Ashish Gupta
 
Deep dive into swift UI
Deep dive into swift UIDeep dive into swift UI
Deep dive into swift UI
OsamaGamal26
 

What's hot (20)

Sqlite
SqliteSqlite
Sqlite
 
Selenium WebDriver
Selenium WebDriverSelenium WebDriver
Selenium WebDriver
 
Testing android apps with espresso
Testing android apps with espressoTesting android apps with espresso
Testing android apps with espresso
 
Unit Testing And Mocking
Unit Testing And MockingUnit Testing And Mocking
Unit Testing And Mocking
 
JUnit Presentation
JUnit PresentationJUnit Presentation
JUnit Presentation
 
MVVM ( Model View ViewModel )
MVVM ( Model View ViewModel )MVVM ( Model View ViewModel )
MVVM ( Model View ViewModel )
 
Swift UI - Declarative Programming [Pramati Technologies]
Swift UI - Declarative Programming [Pramati Technologies]Swift UI - Declarative Programming [Pramati Technologies]
Swift UI - Declarative Programming [Pramati Technologies]
 
Nestjs MasterClass Slides
Nestjs MasterClass SlidesNestjs MasterClass Slides
Nestjs MasterClass Slides
 
Spring Framework - Core
Spring Framework - CoreSpring Framework - Core
Spring Framework - Core
 
TestNG Framework
TestNG Framework TestNG Framework
TestNG Framework
 
Core java concepts
Core java  conceptsCore java  concepts
Core java concepts
 
Automation - web testing with selenium
Automation - web testing with seleniumAutomation - web testing with selenium
Automation - web testing with selenium
 
Unit Testing in Java
Unit Testing in JavaUnit Testing in Java
Unit Testing in Java
 
Spring Boot
Spring BootSpring Boot
Spring Boot
 
How to go about testing in React?
How to go about testing in React? How to go about testing in React?
How to go about testing in React?
 
Selenium
SeleniumSelenium
Selenium
 
Unit testing with JUnit
Unit testing with JUnitUnit testing with JUnit
Unit testing with JUnit
 
Selenium WebDriver training
Selenium WebDriver trainingSelenium WebDriver training
Selenium WebDriver training
 
Jsf presentation
Jsf presentationJsf presentation
Jsf presentation
 
Deep dive into swift UI
Deep dive into swift UIDeep dive into swift UI
Deep dive into swift UI
 

Viewers also liked

JUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit TestsJUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit Tests
John Ferguson Smart Limited
 
Ui testing with espresso
Ui testing with espressoUi testing with espresso
Ui testing with espresso
Droidcon Spain
 
TDD - Cultivating a Beginner's Mind
TDD -  Cultivating a Beginner's MindTDD -  Cultivating a Beginner's Mind
TDD - Cultivating a Beginner's Mind
Shai Yallin
 
Mockito
MockitoMockito
Writing quick and beautiful automation code
Writing quick and beautiful automation codeWriting quick and beautiful automation code
Writing quick and beautiful automation code
Cristian COȚOI
 
使用 Java 上的 future/promise API
使用 Java 上的 future/promise  API使用 Java 上的 future/promise  API
使用 Java 上的 future/promise API
koji lin
 
Testing basics for developers
Testing basics for developersTesting basics for developers
Testing basics for developers
Anton Udovychenko
 
Android Espresso
Android EspressoAndroid Espresso
Android Espresso
Armando Picón Z.
 
Reliable tests with selenium web driver
Reliable tests with selenium web driverReliable tests with selenium web driver
Reliable tests with selenium web driver
PawelPabich
 
Utilizando Espresso e UIAutomator no Teste de Apps Android
Utilizando Espresso e UIAutomator no Teste de Apps AndroidUtilizando Espresso e UIAutomator no Teste de Apps Android
Utilizando Espresso e UIAutomator no Teste de Apps Android
Eduardo Carrara de Araujo
 
"Design and Test First"-Workflow für REST APIs
"Design and Test First"-Workflow für REST APIs"Design and Test First"-Workflow für REST APIs
"Design and Test First"-Workflow für REST APIs
Markus Decke
 
Assertj-core
Assertj-coreAssertj-core
Assertj-core
fbenault
 
Showdown of the Asserts by Philipp Krenn
Showdown of the Asserts by Philipp KrennShowdown of the Asserts by Philipp Krenn
Showdown of the Asserts by Philipp Krenn
JavaDayUA
 
JUnit & AssertJ
JUnit & AssertJJUnit & AssertJ
JUnit & AssertJ
Sunghyouk Bae
 
Property based-testing
Property based-testingProperty based-testing
Property based-testing
fbenault
 
Illia Seleznov - Integration tests for Spring Boot application
Illia Seleznov - Integration tests for Spring Boot applicationIllia Seleznov - Integration tests for Spring Boot application
Illia Seleznov - Integration tests for Spring Boot application
Anna Shymchenko
 
Espresso Barista
Espresso BaristaEspresso Barista
Как заработать денег в CPA
Как заработать денег в CPAКак заработать денег в CPA
Как заработать денег в CPA
Алексей Терехов
 
Espresso testing
Espresso testingEspresso testing
Espresso testing
vodqancr
 
Load-testing 101 for Startups with Artillery.io
Load-testing 101 for Startups with Artillery.ioLoad-testing 101 for Startups with Artillery.io
Load-testing 101 for Startups with Artillery.io
Hassy Veldstra
 

Viewers also liked (20)

JUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit TestsJUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit Tests
 
Ui testing with espresso
Ui testing with espressoUi testing with espresso
Ui testing with espresso
 
TDD - Cultivating a Beginner's Mind
TDD -  Cultivating a Beginner's MindTDD -  Cultivating a Beginner's Mind
TDD - Cultivating a Beginner's Mind
 
Mockito
MockitoMockito
Mockito
 
Writing quick and beautiful automation code
Writing quick and beautiful automation codeWriting quick and beautiful automation code
Writing quick and beautiful automation code
 
使用 Java 上的 future/promise API
使用 Java 上的 future/promise  API使用 Java 上的 future/promise  API
使用 Java 上的 future/promise API
 
Testing basics for developers
Testing basics for developersTesting basics for developers
Testing basics for developers
 
Android Espresso
Android EspressoAndroid Espresso
Android Espresso
 
Reliable tests with selenium web driver
Reliable tests with selenium web driverReliable tests with selenium web driver
Reliable tests with selenium web driver
 
Utilizando Espresso e UIAutomator no Teste de Apps Android
Utilizando Espresso e UIAutomator no Teste de Apps AndroidUtilizando Espresso e UIAutomator no Teste de Apps Android
Utilizando Espresso e UIAutomator no Teste de Apps Android
 
"Design and Test First"-Workflow für REST APIs
"Design and Test First"-Workflow für REST APIs"Design and Test First"-Workflow für REST APIs
"Design and Test First"-Workflow für REST APIs
 
Assertj-core
Assertj-coreAssertj-core
Assertj-core
 
Showdown of the Asserts by Philipp Krenn
Showdown of the Asserts by Philipp KrennShowdown of the Asserts by Philipp Krenn
Showdown of the Asserts by Philipp Krenn
 
JUnit & AssertJ
JUnit & AssertJJUnit & AssertJ
JUnit & AssertJ
 
Property based-testing
Property based-testingProperty based-testing
Property based-testing
 
Illia Seleznov - Integration tests for Spring Boot application
Illia Seleznov - Integration tests for Spring Boot applicationIllia Seleznov - Integration tests for Spring Boot application
Illia Seleznov - Integration tests for Spring Boot application
 
Espresso Barista
Espresso BaristaEspresso Barista
Espresso Barista
 
Как заработать денег в CPA
Как заработать денег в CPAКак заработать денег в CPA
Как заработать денег в CPA
 
Espresso testing
Espresso testingEspresso testing
Espresso testing
 
Load-testing 101 for Startups with Artillery.io
Load-testing 101 for Startups with Artillery.ioLoad-testing 101 for Startups with Artillery.io
Load-testing 101 for Startups with Artillery.io
 

Similar to Writing and using Hamcrest Matchers

Developer Testing Tools Roundup
Developer Testing Tools RoundupDeveloper Testing Tools Roundup
Developer Testing Tools Roundup
John Ferguson Smart Limited
 
Pragmatic unittestingwithj unit
Pragmatic unittestingwithj unitPragmatic unittestingwithj unit
Pragmatic unittestingwithj unit
liminescence
 
Client server part 12
Client server part 12Client server part 12
Client server part 12
fadlihulopi
 
Kitura Todolist tutorial
Kitura Todolist tutorialKitura Todolist tutorial
Kitura Todolist tutorial
Robert F. Dickerson
 
Property Wrappers or how Swift decided to become Java
Property Wrappers or how Swift decided to become JavaProperty Wrappers or how Swift decided to become Java
Property Wrappers or how Swift decided to become Java
Vincent Pradeilles
 
Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
John Ferguson Smart Limited
 
Rhino Mocks
Rhino MocksRhino Mocks
Rhino Mocks
Anand Kumar Rajana
 
Sustaining Test-Driven Development
Sustaining Test-Driven DevelopmentSustaining Test-Driven Development
Sustaining Test-Driven Development
AgileOnTheBeach
 
WD programs descriptions.docx
WD programs descriptions.docxWD programs descriptions.docx
WD programs descriptions.docx
anjani pavan kumar
 
Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."
Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."
Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."
sjabs
 
Java Boilerplate Busters
Java Boilerplate BustersJava Boilerplate Busters
Java Boilerplate Busters
HamletDRC
 
Test-driven Development with AEM
Test-driven Development with AEMTest-driven Development with AEM
Test-driven Development with AEM
Jan Wloka
 
Google guava
Google guavaGoogle guava
Spring data ii
Spring data iiSpring data ii
Spring data ii
명철 강
 
Java Boilerplate Busters
Java Boilerplate BustersJava Boilerplate Busters
Java Boilerplate Busters
HamletDRC
 
08 Queries
08 Queries08 Queries
08 Queries
Ranjan Kumar
 
Introduction to Client-Side Javascript
Introduction to Client-Side JavascriptIntroduction to Client-Side Javascript
Introduction to Client-Side Javascript
Julie Iskander
 
Improving the java type system
Improving the java type systemImproving the java type system
Improving the java type system
João Loff
 
Hadoop Integration in Cassandra
Hadoop Integration in CassandraHadoop Integration in Cassandra
Hadoop Integration in Cassandra
Jairam Chandar
 
Core2 Document - Java SCORE Overview.pptx.pdf
Core2 Document - Java SCORE Overview.pptx.pdfCore2 Document - Java SCORE Overview.pptx.pdf
Core2 Document - Java SCORE Overview.pptx.pdf
ThchTrngGia
 

Similar to Writing and using Hamcrest Matchers (20)

Developer Testing Tools Roundup
Developer Testing Tools RoundupDeveloper Testing Tools Roundup
Developer Testing Tools Roundup
 
Pragmatic unittestingwithj unit
Pragmatic unittestingwithj unitPragmatic unittestingwithj unit
Pragmatic unittestingwithj unit
 
Client server part 12
Client server part 12Client server part 12
Client server part 12
 
Kitura Todolist tutorial
Kitura Todolist tutorialKitura Todolist tutorial
Kitura Todolist tutorial
 
Property Wrappers or how Swift decided to become Java
Property Wrappers or how Swift decided to become JavaProperty Wrappers or how Swift decided to become Java
Property Wrappers or how Swift decided to become Java
 
Clean coding-practices
Clean coding-practicesClean coding-practices
Clean coding-practices
 
Rhino Mocks
Rhino MocksRhino Mocks
Rhino Mocks
 
Sustaining Test-Driven Development
Sustaining Test-Driven DevelopmentSustaining Test-Driven Development
Sustaining Test-Driven Development
 
WD programs descriptions.docx
WD programs descriptions.docxWD programs descriptions.docx
WD programs descriptions.docx
 
Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."
Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."
Kamil Chmielewski, Jacek Juraszek - "Hadoop. W poszukiwaniu złotego młotka."
 
Java Boilerplate Busters
Java Boilerplate BustersJava Boilerplate Busters
Java Boilerplate Busters
 
Test-driven Development with AEM
Test-driven Development with AEMTest-driven Development with AEM
Test-driven Development with AEM
 
Google guava
Google guavaGoogle guava
Google guava
 
Spring data ii
Spring data iiSpring data ii
Spring data ii
 
Java Boilerplate Busters
Java Boilerplate BustersJava Boilerplate Busters
Java Boilerplate Busters
 
08 Queries
08 Queries08 Queries
08 Queries
 
Introduction to Client-Side Javascript
Introduction to Client-Side JavascriptIntroduction to Client-Side Javascript
Introduction to Client-Side Javascript
 
Improving the java type system
Improving the java type systemImproving the java type system
Improving the java type system
 
Hadoop Integration in Cassandra
Hadoop Integration in CassandraHadoop Integration in Cassandra
Hadoop Integration in Cassandra
 
Core2 Document - Java SCORE Overview.pptx.pdf
Core2 Document - Java SCORE Overview.pptx.pdfCore2 Document - Java SCORE Overview.pptx.pdf
Core2 Document - Java SCORE Overview.pptx.pdf
 

Recently uploaded

FIDO Munich Seminar FIDO Automotive Apps.pptx
FIDO Munich Seminar FIDO Automotive Apps.pptxFIDO Munich Seminar FIDO Automotive Apps.pptx
FIDO Munich Seminar FIDO Automotive Apps.pptx
FIDO Alliance
 
Using ScyllaDB for Real-Time Write-Heavy Workloads
Using ScyllaDB for Real-Time Write-Heavy WorkloadsUsing ScyllaDB for Real-Time Write-Heavy Workloads
Using ScyllaDB for Real-Time Write-Heavy Workloads
ScyllaDB
 
TrustArc Webinar - Innovating with TRUSTe Responsible AI Certification
TrustArc Webinar - Innovating with TRUSTe Responsible AI CertificationTrustArc Webinar - Innovating with TRUSTe Responsible AI Certification
TrustArc Webinar - Innovating with TRUSTe Responsible AI Certification
TrustArc
 
Getting Ready for Copilot for Microsoft 365 with Governance Features in Share...
Getting Ready for Copilot for Microsoft 365 with Governance Features in Share...Getting Ready for Copilot for Microsoft 365 with Governance Features in Share...
Getting Ready for Copilot for Microsoft 365 with Governance Features in Share...
Juan Carlos Gonzalez
 
Easy Compliance is Continuous Compliance
Easy Compliance is Continuous ComplianceEasy Compliance is Continuous Compliance
Easy Compliance is Continuous Compliance
Anchore
 
FIDO Munich Seminar In-Vehicle Payment Trends.pptx
FIDO Munich Seminar In-Vehicle Payment Trends.pptxFIDO Munich Seminar In-Vehicle Payment Trends.pptx
FIDO Munich Seminar In-Vehicle Payment Trends.pptx
FIDO Alliance
 
Discovery Series - Zero to Hero - Task Mining Session 1
Discovery Series - Zero to Hero - Task Mining Session 1Discovery Series - Zero to Hero - Task Mining Session 1
Discovery Series - Zero to Hero - Task Mining Session 1
DianaGray10
 
FIDO Munich Seminar Workforce Authentication Case Study.pptx
FIDO Munich Seminar Workforce Authentication Case Study.pptxFIDO Munich Seminar Workforce Authentication Case Study.pptx
FIDO Munich Seminar Workforce Authentication Case Study.pptx
FIDO Alliance
 
The Path to General-Purpose Robots - Coatue
The Path to General-Purpose Robots - CoatueThe Path to General-Purpose Robots - Coatue
The Path to General-Purpose Robots - Coatue
Razin Mustafiz
 
Project Delivery Methodology on a page with activities, deliverables
Project Delivery Methodology on a page with activities, deliverablesProject Delivery Methodology on a page with activities, deliverables
Project Delivery Methodology on a page with activities, deliverables
CLIVE MINCHIN
 
DefCamp_2016_Chemerkin_Yury_--_publish.pdf
DefCamp_2016_Chemerkin_Yury_--_publish.pdfDefCamp_2016_Chemerkin_Yury_--_publish.pdf
DefCamp_2016_Chemerkin_Yury_--_publish.pdf
Yury Chemerkin
 
Blue Screen Of Death | Windows Down | Biggest IT failure
Blue Screen Of Death | Windows Down | Biggest IT failureBlue Screen Of Death | Windows Down | Biggest IT failure
Blue Screen Of Death | Windows Down | Biggest IT failure
Dexbytes Infotech Pvt Ltd
 
Scaling Vector Search: How Milvus Handles Billions+
Scaling Vector Search: How Milvus Handles Billions+Scaling Vector Search: How Milvus Handles Billions+
Scaling Vector Search: How Milvus Handles Billions+
Zilliz
 
Webinar: Transforming Substation Automation with Open Source Solutions
Webinar: Transforming Substation Automation with Open Source SolutionsWebinar: Transforming Substation Automation with Open Source Solutions
Webinar: Transforming Substation Automation with Open Source Solutions
DanBrown980551
 
"Hands-on development experience using wasm Blazor", Furdak Vladyslav.pptx
"Hands-on development experience using wasm Blazor", Furdak Vladyslav.pptx"Hands-on development experience using wasm Blazor", Furdak Vladyslav.pptx
"Hands-on development experience using wasm Blazor", Furdak Vladyslav.pptx
Fwdays
 
UiPath Community Day Amsterdam presentations
UiPath Community Day Amsterdam presentationsUiPath Community Day Amsterdam presentations
UiPath Community Day Amsterdam presentations
UiPathCommunity
 
Multimodal Embeddings (continued) - South Bay Meetup Slides
Multimodal Embeddings (continued) - South Bay Meetup SlidesMultimodal Embeddings (continued) - South Bay Meetup Slides
Multimodal Embeddings (continued) - South Bay Meetup Slides
Zilliz
 
Perth MuleSoft Meetup July 2024
Perth MuleSoft Meetup July 2024Perth MuleSoft Meetup July 2024
Perth MuleSoft Meetup July 2024
Michael Price
 
FIDO Munich Seminar: FIDO Tech Principles.pptx
FIDO Munich Seminar: FIDO Tech Principles.pptxFIDO Munich Seminar: FIDO Tech Principles.pptx
FIDO Munich Seminar: FIDO Tech Principles.pptx
FIDO Alliance
 
Self-Healing Test Automation Framework - Healenium
Self-Healing Test Automation Framework - HealeniumSelf-Healing Test Automation Framework - Healenium
Self-Healing Test Automation Framework - Healenium
Knoldus Inc.
 

Recently uploaded (20)

FIDO Munich Seminar FIDO Automotive Apps.pptx
FIDO Munich Seminar FIDO Automotive Apps.pptxFIDO Munich Seminar FIDO Automotive Apps.pptx
FIDO Munich Seminar FIDO Automotive Apps.pptx
 
Using ScyllaDB for Real-Time Write-Heavy Workloads
Using ScyllaDB for Real-Time Write-Heavy WorkloadsUsing ScyllaDB for Real-Time Write-Heavy Workloads
Using ScyllaDB for Real-Time Write-Heavy Workloads
 
TrustArc Webinar - Innovating with TRUSTe Responsible AI Certification
TrustArc Webinar - Innovating with TRUSTe Responsible AI CertificationTrustArc Webinar - Innovating with TRUSTe Responsible AI Certification
TrustArc Webinar - Innovating with TRUSTe Responsible AI Certification
 
Getting Ready for Copilot for Microsoft 365 with Governance Features in Share...
Getting Ready for Copilot for Microsoft 365 with Governance Features in Share...Getting Ready for Copilot for Microsoft 365 with Governance Features in Share...
Getting Ready for Copilot for Microsoft 365 with Governance Features in Share...
 
Easy Compliance is Continuous Compliance
Easy Compliance is Continuous ComplianceEasy Compliance is Continuous Compliance
Easy Compliance is Continuous Compliance
 
FIDO Munich Seminar In-Vehicle Payment Trends.pptx
FIDO Munich Seminar In-Vehicle Payment Trends.pptxFIDO Munich Seminar In-Vehicle Payment Trends.pptx
FIDO Munich Seminar In-Vehicle Payment Trends.pptx
 
Discovery Series - Zero to Hero - Task Mining Session 1
Discovery Series - Zero to Hero - Task Mining Session 1Discovery Series - Zero to Hero - Task Mining Session 1
Discovery Series - Zero to Hero - Task Mining Session 1
 
FIDO Munich Seminar Workforce Authentication Case Study.pptx
FIDO Munich Seminar Workforce Authentication Case Study.pptxFIDO Munich Seminar Workforce Authentication Case Study.pptx
FIDO Munich Seminar Workforce Authentication Case Study.pptx
 
The Path to General-Purpose Robots - Coatue
The Path to General-Purpose Robots - CoatueThe Path to General-Purpose Robots - Coatue
The Path to General-Purpose Robots - Coatue
 
Project Delivery Methodology on a page with activities, deliverables
Project Delivery Methodology on a page with activities, deliverablesProject Delivery Methodology on a page with activities, deliverables
Project Delivery Methodology on a page with activities, deliverables
 
DefCamp_2016_Chemerkin_Yury_--_publish.pdf
DefCamp_2016_Chemerkin_Yury_--_publish.pdfDefCamp_2016_Chemerkin_Yury_--_publish.pdf
DefCamp_2016_Chemerkin_Yury_--_publish.pdf
 
Blue Screen Of Death | Windows Down | Biggest IT failure
Blue Screen Of Death | Windows Down | Biggest IT failureBlue Screen Of Death | Windows Down | Biggest IT failure
Blue Screen Of Death | Windows Down | Biggest IT failure
 
Scaling Vector Search: How Milvus Handles Billions+
Scaling Vector Search: How Milvus Handles Billions+Scaling Vector Search: How Milvus Handles Billions+
Scaling Vector Search: How Milvus Handles Billions+
 
Webinar: Transforming Substation Automation with Open Source Solutions
Webinar: Transforming Substation Automation with Open Source SolutionsWebinar: Transforming Substation Automation with Open Source Solutions
Webinar: Transforming Substation Automation with Open Source Solutions
 
"Hands-on development experience using wasm Blazor", Furdak Vladyslav.pptx
"Hands-on development experience using wasm Blazor", Furdak Vladyslav.pptx"Hands-on development experience using wasm Blazor", Furdak Vladyslav.pptx
"Hands-on development experience using wasm Blazor", Furdak Vladyslav.pptx
 
UiPath Community Day Amsterdam presentations
UiPath Community Day Amsterdam presentationsUiPath Community Day Amsterdam presentations
UiPath Community Day Amsterdam presentations
 
Multimodal Embeddings (continued) - South Bay Meetup Slides
Multimodal Embeddings (continued) - South Bay Meetup SlidesMultimodal Embeddings (continued) - South Bay Meetup Slides
Multimodal Embeddings (continued) - South Bay Meetup Slides
 
Perth MuleSoft Meetup July 2024
Perth MuleSoft Meetup July 2024Perth MuleSoft Meetup July 2024
Perth MuleSoft Meetup July 2024
 
FIDO Munich Seminar: FIDO Tech Principles.pptx
FIDO Munich Seminar: FIDO Tech Principles.pptxFIDO Munich Seminar: FIDO Tech Principles.pptx
FIDO Munich Seminar: FIDO Tech Principles.pptx
 
Self-Healing Test Automation Framework - Healenium
Self-Healing Test Automation Framework - HealeniumSelf-Healing Test Automation Framework - Healenium
Self-Healing Test Automation Framework - Healenium
 

Writing and using Hamcrest Matchers

  • 1. Hamcrest Matchers assertThat(audience, is(payingAttention())); Writing and using them for assertions, mocking and behavioral verification
  • 2. What is Hamcrest? According to the project homepage, [Hamcrest] provides a library of matcher objects (also known as constraints or predicates) allowing 'match' rules to be defined declaratively, to be used in other frameworks. Typical scenarios include testing frameworks, mocking libraries and UI validation rules. Hamcrest is not a testing library: it just happens that matchers are very useful for testing.
  • 3. Typical usage example Actual value assertThat( someString, is(equalTo(someOtherString)) ); Expectation on the value, represented as a Matcher
  • 4. Wait – but what’s wrong with assertEquals? assertEquals(someString, someOtherString) This looks just as good, doesn’t it? assertEquals( cat.getName(), otherCat.getName()) Not so bad, either
  • 5. However, What about collections? assertEquals(someKitten, cat.getKittens().iterator().next()) This works if our kitten is the first element in the collection, but what about asserting that the kitten exists anywhere in the collection?
  • 6. Well, we can do this: boolean found = false; for (Kitten kitten : cat.getKittens()) { if (kitten.equals(someKitten)) found = true; } assertTrue(found);
  • 7. But don’t you prefer this? Iterable<Kitten> assertThat( cat.getKittens(), hasItem(someKitten)) Matcher on Iterable<Kitten> that accepts a Matcher<Kitten>
  • 8. OK, so how does this work?
  • 9. Basic Matchers A Matcher is initialized with the expected values, which are compared against the actual object we’re matching against when invoking the matcher.
  • 10. IsEqual Matcher class IsEqual<T> extends BaseMatcher<T> { private final Object object; // c’tor omitted for readability public boolean matches(Object arg) { return object.equals(arg); } }
  • 11. StringEndsWith Matcher class StringEndsWith <T> extends BaseMatcher<T> { private final String suffix; // c’tor omitted for readability public boolean matches(String s) { return s.endsWith(suffix); } }
  • 13. Mockito in one slide CatShop catShop = mock(CatShop.class); when(catShop.purchase(somePurchaseRequest ).thenReturn(someCat) Creating the mock ... do some work Stubbing the mock verify(catShop) Behavior verification .purchase(expectedPurchaseRequest)
  • 14. Without Hamcrest CatPurchase catPurchase = new CatPurchase(); catPurchase.setBreed(“Brittish”); when(catShop.purchase(catPurchase)) ).thenReturn(somePreviouslyStubbedCat) However, this will force us to set all other fields of the CatPurchase class, since Mockito will perform an exact match comparison between our instance and the actual one
  • 15. Of course, you could do this: when( catShop.purchase( any(CatPurchaseDTO.class)) ).thenReturn(somePreviouslyStubbedCat) This works, but lacks the benefit of asserting that our operation is only valid for the expected input
  • 16. The solution: use argThat() Mockito helper that creates an argument matcher from when( a Hamcrest matcher catShop.purchase(argThat( hasPropertyWithValue( “breed”, startsWith(“Brittish”)))) ).thenReturn(somePreviouslyStubbedCat) Hamcrest matcher that accepts a Java Bean property name and a nested value matcher
  • 17. Using for behavioral verification CatDao catDao = mock(CatDao.class); CatStore catStore = new CatStore (catDao);with a Catcall to Verify that there was a CatDao.update() instance, catStore.saveOrUpdate(existingCat); the ‘name’ property is for which “felix” and the ‘kittens’ property is an verify(catDao).update(argThat( Iterable containing two kittens, kitten1 and kitten2 allOf( hasPropertyWithValue(“name”, “felix”), hasPropertyWithValue(“kittens”, hasItems(kitten1, kitten2)))));
  • 19. Writing your own matchers In the previous examples, we used the hasPropertyWithValue() matcher, which, while allowing for fluent assertions or stubbing, has the disadvantage of not being type-safe. This is where writing custom matchers becomes useful (or, as some would say, necessary).
  • 20. The Matcher<T> hierarchy abstract class TypeSafeMatcher<T> extends BaseMatcher<T> { boolean matchesSafely(T item); } interface Matcher<T> extends SelfDescribing { boolean matches(Object item); } interface SelfDescribing { void describeTo(Description description); }
  • 21. Dissecting some Wix matchers class HostMatcher extends TypeSafeMatcher<WixUrl> { private final Matcher<String> host; // c’tor omitted for readability public boolean matchesSafely(WixUrl url) { return host.matches(url.host); Nested matcher that } will be replayed on the Actual value being actual value matched against public void describeTo(Description description) { description.appendText("Host that matches ").appendValue(host); we write a Here } readable description of our expected value public static HostMatcher hasHost(Matcher<String> host)A utility factory method for { return new HostMatcher(host); fluently creating this } matcher. Not mandatory } but very convenient.
  • 22. Using our matcher WixUrl url = new WixUrl(“http://www.wix.com/some/path”); assertThat(url, hasHost(is(“www.wix.com”))); ✔ assertThat(url, hasHost(endsWith(“wix.com”))); ✔ assertThat(url, hasHost(is(“google.com”))); ✗ java.lang.AssertionError: Expected: Host that matches <is ”google.com"> got: <http://www.wix.com/some/path>
  • 23. Another URL matcher class WixUrlParamMatcher extends TypeSafeMatcher<WixUrl> { private final Matcher<String> name; // c’tor omitted for readability url.params is a Map<String, String>, so private final Matcher<String> value; we create a matcher for a map entry around our name and value matchers public boolean matchesSafely(WixUrl url) { replay it against the actual value and return hasEntry(name, value).matches(url.params); } public void describeTo(Description description) { description .appendText("Param with name ").appendValue(name) .appendText(" and value ").appendValue(value); } }
  • 24. Using the two matchers together String s = “www.wix.com?p=v1&p=v2&p3=v3”; WixUrl url = new WixUrl(s); assertThat(url, allOf( hasHost(is(“www.wix.com”)), hasParam(is(“p”), anyOf(is(“v1”), is(“v2”))), hasParam(is(“p3”), startsWith(“v”))));
  • 25. But wait – my URL is a String! Sometimes you’ll have matchers that accept a specific type, such as WixUrl or XML Document. For this purpose, use a wrapping matcher that performs the conversion for you: class StringAsUrlMatcher extends TypeSafeMatcher<String> { private final Matcher<WixUrl> urlMatcher; public boolean matchesSafely(String urlString) { return matcher.matches(new WixUrl(urlString)); } public void describeTo(Description description) { description.appendText("Url that matches ") .appendDescriptionOf(urlMatcher); } }
  • 26. Ad-Hoc matchers for readable tests
  • 27. Consider the following class class Proxy { private final HttpClient httpClient; private String targetUrl; public String handle (String path) { httpClient.execute(// some HttpGet); } }
  • 28. The HttpClient interface public HttpResponse execute(HttpGet get); Our class under test is expected to replace the domain in path with targetUrl, thus serving as an HTTP Proxy. We would like to stub and verify the HttpGet parameter to make sure it builds the proxy URL properly.
  • 29. My test looks something like this HttpClient client = mock(HttpClient.class); String url = “http://www.example.com/”; {…} handler = new Proxy(client, url); when(client.execute({www.a.com/path})) .thenReturn(someResponse); handler.handle(“www.a.com/path”); verify(client).execute({www.example.com/path});
  • 30. The solution Matcher<HttpGet> HttpGet(final Matcher<String> urlMatcher) { return new TypeSafeMatcher<HttpGet>() { public boolean matchesSafely(HttpGet httpGet) { return urlMatcher.matches(httpGet.getURI().toString())); } public void describeTo(Description description) { description.appendText("HttpGet with url ") .appendDescriptionOf(urlMatcher); } }; }
  • 31. Usage of the HttpGet matcher when(handler.execute(argThat( is(HttpGet(startsWith(“http://www.a.com”)))))) .thenReturn(response); handler.handle(“http://www.a.com/some/path”); verify(client).execute(argThat(is(HttpGet( is(“http://www.example.com/some/path”)))));
  • 32. The plot thickens Moments after triumphantly running the test I realized that in addition to verifying that the request went to the appropriate URL, I had to verify that some – but not all – HTTP headers were copied to the proxy request and some new ones were added to it.
  • 33. Ad-hoc matchers to the rescue 1) Add the following parameter to the HttpGet method: final Matcher<Header[]> headersMatcher 2) Change the matchesSafetly() method: public boolean matchesSafely(HttpGet httpGet) { return urlMatcher.matches(httpGet.getURI().toString()) && headersMatcher.matches(httpGet.getAllHeaders()); }
  • 34. Ad-hoc matchers to the rescue 3) Write a matcher for the Header class: Matcher<Header> Header( final Matcher<String> name, final Matcher<String> value) { return new TypeSafeMatcher<Header>() { public boolean matchesSafely(Header header) { return name.matches(header.getName()) && value.matches(header.getValue()); } } }
  • 35. Putting it all together verify(client).execute(argThat(is(HttpGet( that the X-Wix-Base-Uri header Asserts contains the expected value (using the is({URL matcher omitted for readability}), WixUrl matchers we’ve seen before). allOf( hasItemInArray( Header( is("X-Wix-Base-Uri"), Asserts that there’s no header by isUrlThat( the name of X-Seen-By, no matter what value it has hasHost(“www.wix.com”), hasPath(myPath)))), not(hasItemInArray( Header(is("X-Seen-By"), any(String.class)))) )))));
  • 36. Questions? shaiy@wix.com http://il.linkedin.com/in/electricmonk http://twitter.com/shaiyallin

Editor's Notes

  1. This is a simplified version of the actual matcher from Hamcrest Core
  2. For those of you who’re not familiar with Mockito, here’s how you use it
  3. This has the disadvantage of being type-unsafe, but we’ll get back to this point later on.
  4. Like the previous example, this is type-unsafe because we’re not sure that the Cat class even has a field named “kittens”, let alone its type
  5. Matcher is the common ancestor for all Hamcrest matchers. Note that I removed a warning urging you not to implement Matcher&lt;T&gt;, extending BaseMatcher&lt;T&gt; instead.In most cases, you’ll want to extend TypeSafeMatcher&lt;T&gt;
  6. This matcher works on the WixUrl class, which is a type-safe URL builder class from the Wix infrastructure.It’s a good example for the simple, yet somewhat confusing, structure of a matcher. Note that this matcher has one member, which is another string matcher for specifying the expected value. We could’ve used a string here, but using a Matcher&lt;String&gt; allows us to be more flexible when using this matcher.This pattern of replaying a matcher against the actual value is a core principle of Matcher programming.Note that our matcher extends TypeSafeMatcher, which implements the Matcher.matches() method and delegates to the matchesSafely() method after performing a type assertion followed by a cast.
  7. Why do we need a Url matcher? Sometimes we don’t care about the query string, the host, the port, the protocol, etc. We could’ve used a string matcher such as contains() or endsWith() but this is more type safe, readable and illustrates the tested behavior more clearly.Note how the assertion error is much more readable than the one produced by assertEquals()
  8. This one takes two matchers, one for the parameter name and one for the parameter value.Note another principle introduced here, that of creating a new matcher wrapping our matchers and replaying it against the actual value. Thus, we abstract away from the test the fact the WixUrl.params is a map. In fact, we lately changed it from a Map&lt;String, String&gt; to a Multimap&lt;String, String&gt; without breaking any test – I just changed the field type and the appropriate matcher class.
  9. Note the use of the allOf() and anyOf() aggregate matchers that represent boolean AND and OR operations, respectively.
  10. Based on a true storyThis class accepts an instance of HttpClient (Apache HttpComponents 4.0). I wanted to give it a mock of HttpClient, then stub and verify it.
  11. I needed to be able to write matchers for the HttpGet class, for two reasons:1) It was much more readable than constructing an instance of it2) HttpGet takes on parameter, URI, and contains logic that deals with the HTTP protocol itself – not something that’s relevant for the test
  12. Note, again, how we replay the expected value matcher against the actual value. This prevents the need to construct our own instance on HttpGet and populate it with the expected value. Also note that this is a factory method, creating an anonymous class. The method starts with a capital letter and is named according to the name of the class we’re matching against. This is a convention we developed here at Wix, but we find it useful and clear.
  13. The use case here is that the proxy should send all traffic from www.wix.com/ to theproxied server, appending any nested path.Note that response can be either a real object constructed beforehand or a mock, but the mock must also be constructed before calling the when() method because of some Mockito limitation.Also note the reuse of our matcher both for stubbing the mock and verifying the desired behavior.
  14. The matcher is for a Header array because HttpGet.getAllHeaders() returns an array
  15. Note that without using Hamcrest, there’s no straightforward way to test for the inexistence of a value