create your mockito.ArgumentMatcher

When testing you usually need to mock. I mock mostly using Mockito and usually, I stub using when and verify calls using verify.

Normally you will want to verify that a given method has called with specific parameters or that a mocked method returns the desired value only when called also with specific parameters.

In the following class, an article is the same if its id is the same. We can, however, be interested in match the article using its contents (tile and text) instead of its database id.

public class Article {

  private int id;
  private String title;
  private String text;

  public Article(int id, String title, String text) {
    this.id = id;
    this.title = title;
    this.text = text;
  }

  public int getId() {
    return id;
  }

  public String getTitle() {
    return title;
  }

  public String getText() {
    return text;
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Article article = (Article) o;
    return id == article.id;
  }

  @Override
  public int hashCode() {
    return Objects.hash(id);
  }
}

Usually, it is enough to use the Mocikto.eq() ArgumentMatcher that will use the Object.equals() method.

 Mockito.verify(publication).addArticle(Mockito.eq(article));

However, if we want to match against its contents, we need a new matcher “ArticleMatcher” that compares title and text. Therefore, I will just create a class ArticleMatcher implements ArgumentMatcher

class ArticleMatcher implements ArgumentMatcher
<Article> {

  public final Article article;

  /**
   * register our matcher.
   */
  public static Article eq(Article article) {
    mockingProgress().getArgumentMatcherStorage().reportMatcher(new ArticleMatcher(article));
    return null;
  }

  public ArticleMatcher(Article article) {
    this.article = article;
  }

  /**
   * Implements matches method with our matching logic.
   * @param article
   * @return
   */
  @Override
  public boolean matches(Article article) {
    return this.article.getText().equalsIgnoreCase(article.getText());
  }

  public String toString() {
    return "<ArticleMatcher>";
  }
}

Now we can use our ArgumentMutcher to create stubs and verify calls:

class ArticleTest {

  @Test
  void checkVerify() {

    Article article1 = new Article(1, "someText", "title");
    Article article2 = new Article(2, "someText", "title");
    Article article3 = new Article(3, "someText", "title");

    Publication publication = Mockito.spy(Publication.class);
    publication.addArticle(article1);

    Mockito.verify(publication).addArticle(ArticleMatcher.eq(article2));
    Mockito.verify(publication, Mockito.times(0)).addArticle(Mockito.eq(article3));

  }

  @Test
  void checkStub() {

    Article article1 = new Article(1, "someText", "title");
    Article article2 = new Article(2, "someText", "title");
    Article article3 = new Article(3, "someText", "title");

    Publication publication = Mockito.spy(Publication.class);
    Mockito.when(publication.getArticlesLike(ArticleMatcher.eq(article2))).thenReturn(Arrays.asList(article1, article2));

    List<Article> articles = publication.getArticlesLike(article3);
    Assertions.assertEquals(2, articles.size());
    Assertions.assertTrue(articles.contains(article1));
    Assertions.assertTrue(articles.contains(article2));
    Assertions.assertFalse(articles.contains(article3));
  }
}

So easy 🙂

code in github

Capturing arguments with mockito

EncryptedFileInfo info = cut.storeEncryptedFile(encryptionSecret, plainContents, fileName);

ArgumentCaptor<byte[]> argument = ArgumentCaptor.forClass(byte[].class);

verify(cut).createFileAndAdd(eq(fileName), argument.capture());
byte[] encryptedContent = argument.getAllValues().get(0);

Where intercepted method is:

void createFileAndAdd(String fileName, byte[] encryptedContents);

Runing test from jar with Junit5

java -jar junit-platform-console-standalone-1.3.0-M1.jar -n .*IT -scan-class-path -cp target\test-classes\(test.jar) -cp target\app-jar-with-dependencies.jar
where:
  • -n .*IT is a regex looking for files suffixed with IT (default: ^(Test.*|.+[.$]Test.*|.*Tests?)$)
  • -scan-class-path look for tests on classpath
  • -cp: the classpath

Bonus:

to compile test classes:  mvn test-compile compile

to create test jar:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>3.1.0</version>
    <executions>
        <execution>
            <goals>
                <goal>test-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>