Merge branch 'stable-3.0' into stable-3.1

* stable-3.0:
  Extend CommitMessageFetcher to handle non-commit objects

Change-Id: If3ee7bcf1d281f93673fbb95a04f896726617d47
diff --git a/WORKSPACE b/WORKSPACE
index 60d9408..8308b76 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,24 +3,24 @@
 load("//:bazlets.bzl", "load_bazlets")
 
 load_bazlets(
-    commit = "c2227415d5044f8439bd47edffb0f052f8da2ac5",
+    commit = "d826d85285bb22d3fe817fe165a7e1d3472f65fa",
     # local_path = "/home/<user>/projects/bazlets",
 )
 
 # Snapshot Plugin API
-#load(
-#    "@com_googlesource_gerrit_bazlets//:gerrit_api_maven_local.bzl",
-#    "gerrit_api_maven_local",
-#)
-
-# Release Plugin API
 load(
-    "@com_googlesource_gerrit_bazlets//:gerrit_api.bzl",
-    "gerrit_api",
+    "@com_googlesource_gerrit_bazlets//:gerrit_api_maven_local.bzl",
+    "gerrit_api_maven_local",
 )
 
+# Release Plugin API
+#load(
+#    "@com_googlesource_gerrit_bazlets//:gerrit_api.bzl",
+#    "gerrit_api",
+#)
+
 # Load release Plugin API
-gerrit_api()
+#gerrit_api()
 
 # Load snapshot Plugin API
-#gerrit_api_maven_local()
+gerrit_api_maven_local()
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfig.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfig.java
index 6a5eda4..9dda01f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfig.java
@@ -16,11 +16,12 @@
 
 import static java.util.stream.Collectors.toList;
 
+import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.common.data.AccessSection;
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.entities.Project.NameKey;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.api.projects.CommentLinkInfo;
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.client.Project.NameKey;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.PluginConfig;
 import com.google.gerrit.server.config.PluginConfigFactory;
@@ -44,13 +45,11 @@
 import java.util.Optional;
 import java.util.regex.Pattern;
 import org.eclipse.jgit.lib.Config;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class ItsConfig {
   private static final String PLUGIN = "plugin";
 
-  private static final Logger log = LoggerFactory.getLogger(ItsConfig.class);
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   private final String pluginName;
   private final ProjectCache projectCache;
@@ -89,17 +88,16 @@
         || event instanceof RefUpdatedEvent) {
       return isEnabled(event.getProjectNameKey(), event.getRefName());
     }
-    log.debug("Event {} not recognised and ignored", event);
+    logger.atFine().log("Event %s not recognised and ignored", event);
     return false;
   }
 
   public boolean isEnabled(Project.NameKey projectNK, String refName) {
     ProjectState projectState = projectCache.get(projectNK);
     if (projectState == null) {
-      log.error(
-          "Failed to check if {} is enabled for project {}: Project not found",
-          pluginName,
-          projectNK.get());
+      logger.atSevere().log(
+          "Failed to check if %s is enabled for project %s: Project not found",
+          pluginName, projectNK.get());
       return false;
     }
     return isEnforcedByAnyParentProject(refName, projectState)
@@ -257,7 +255,8 @@
       try {
         return pluginCfgFactory.getFromProjectConfigWithInheritance(projectName, pluginName);
       } catch (NoSuchProjectException e) {
-        log.error("Cannot access " + projectName + " configuration for plugin " + pluginName, e);
+        logger.atSevere().withCause(e).log(
+            "Cannot access %s configuration for plugin %s", projectName, pluginName);
       }
     }
     return new PluginConfig(pluginName, new Config());
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsFacade.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsFacade.java
index db2857b..6531ed7 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsFacade.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsFacade.java
@@ -31,6 +31,14 @@
 
   public void addComment(String issueId, String comment) throws IOException;
 
+  /**
+   * Sets a field on the issue to an event property.
+   *
+   * @param issueId The issue to set the field on
+   * @param value The name of the property to set the issues's field to
+   * @param fieldId The field on the issue to set
+   * @throws IOException if an error occurred
+   */
   default void addValueToField(String issueId, String value, String fieldId) throws IOException {
     throw new UnsupportedOperationException(
         "add-value-to-field is not currently implemented by " + getClass());
@@ -38,6 +46,13 @@
 
   public void performAction(String issueId, String actionName) throws IOException;
 
+  /**
+   * Creates a new version on a given ITS.
+   *
+   * @param itsProject the ITS to create the version on
+   * @param version the version to create
+   * @throws IOException if an error occurred
+   */
   default void createVersion(String itsProject, String version) throws IOException {
     throw new UnsupportedOperationException("create-version is not implemented by " + getClass());
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsFacadeFactory.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsFacadeFactory.java
index 4e2f035..b4cad31 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsFacadeFactory.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsFacadeFactory.java
@@ -14,7 +14,7 @@
 
 package com.googlesource.gerrit.plugins.its.base.its;
 
-import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.entities.Project;
 
 /* An interface to get server information from child its-plugin embedded in the ItsFacade implementation */
 public interface ItsFacadeFactory {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/its/NoopItsFacade.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/its/NoopItsFacade.java
index ecf3a6f..ba7fb14 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/its/NoopItsFacade.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/its/NoopItsFacade.java
@@ -14,73 +14,55 @@
 
 package com.googlesource.gerrit.plugins.its.base.its;
 
+import com.google.common.flogger.FluentLogger;
 import java.io.IOException;
 import java.net.URL;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /** An ITS facade doing nothing, it's configured when no ITS are referenced in config */
 public class NoopItsFacade implements ItsFacade {
-
-  private Logger log = LoggerFactory.getLogger(NoopItsFacade.class);
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   @Override
   public void addComment(String issueId, String comment) throws IOException {
-    if (log.isDebugEnabled()) {
-      log.debug("addComment({},{})", issueId, comment);
-    }
+    logger.atFine().log("addComment(%s,%s)", issueId, comment);
   }
 
   @Override
   public void addValueToField(String issueId, String value, String fieldId) throws IOException {
-    if (log.isDebugEnabled()) {
-      log.debug("addValueToField({},{},{})", issueId, fieldId, value);
-    }
+    logger.atFine().log("addValueToField(%s,%s,%s)", issueId, fieldId, value);
   }
 
   @Override
   public void addRelatedLink(String issueId, URL relatedUrl, String description)
       throws IOException {
-    if (log.isDebugEnabled()) {
-      log.debug("addRelatedLink({},{},{})", issueId, relatedUrl, description);
-    }
+    logger.atFine().log("addRelatedLink(%s,%s,%s)", issueId, relatedUrl, description);
   }
 
   @Override
   public boolean exists(String issueId) throws IOException {
-    if (log.isDebugEnabled()) {
-      log.debug("exists({})", issueId);
-    }
+    logger.atFine().log("exists(%s)", issueId);
     return false;
   }
 
   @Override
   public void performAction(String issueId, String actionName) throws IOException {
-    if (log.isDebugEnabled()) {
-      log.debug("performAction({},{})", issueId, actionName);
-    }
+    logger.atFine().log("performAction(%s,%s)", issueId, actionName);
   }
 
   @Override
   public void createVersion(String itsProject, String version) {
-    if (log.isDebugEnabled()) {
-      log.debug("createVersion({},{})", itsProject, version);
-    }
+    logger.atFine().log("createVersion(%s,%s)", itsProject, version);
   }
 
   @Override
   public String healthCheck(Check check) throws IOException {
-    if (log.isDebugEnabled()) {
-      log.debug("healthCheck()");
-    }
+    logger.atFine().log("healthCheck()");
     return "{\"status\"=\"ok\",\"system\"=\"not configured\",}";
   }
 
   @Override
   public String createLinkForWebui(String url, String text) {
-    if (log.isDebugEnabled()) {
-      log.debug("createLinkForWebui({},{})", url, text);
-    }
+    logger.atFine().log("createLinkForWebui(%s,%s)", url, text);
     return "";
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/its/SingleItsServer.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/its/SingleItsServer.java
index 08bfe62..dc0a79f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/its/SingleItsServer.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/its/SingleItsServer.java
@@ -14,7 +14,7 @@
 
 package com.googlesource.gerrit.plugins.its.base.its;
 
-import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.entities.Project;
 import com.google.inject.Inject;
 
 /* An ItsServer implementation that should be bound
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/util/CommitMessageFetcher.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/util/CommitMessageFetcher.java
index ed1c6b3..1d5188d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/util/CommitMessageFetcher.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/util/CommitMessageFetcher.java
@@ -1,6 +1,7 @@
 package com.googlesource.gerrit.plugins.its.base.util;
 
-import com.google.gerrit.reviewdb.client.Project;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.Project;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.inject.Inject;
 import java.io.IOException;
@@ -9,11 +10,9 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevObject;
 import org.eclipse.jgit.revwalk.RevWalk;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class CommitMessageFetcher {
-  private static final Logger log = LoggerFactory.getLogger(CommitMessageFetcher.class);
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   private final GitRepositoryManager repoManager;
 
@@ -47,9 +46,8 @@
     try {
       ret = fetch(projectName, objectId);
     } catch (IOException e) {
-      log.error(
-          "Could not fetch commit message for commit " + objectId + " of project " + projectName,
-          e);
+      logger.atSevere().withCause(e).log(
+          "Could not fetch commit message for commit %s of project %s", objectId, projectName);
     }
     return ret;
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractor.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractor.java
index cb577c5..6131ed4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractor.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractor.java
@@ -5,12 +5,13 @@
 import com.google.common.base.Strings;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.PatchSet;
 import com.google.gerrit.extensions.api.GerritApi;
 import com.google.gerrit.extensions.client.ListChangesOption;
 import com.google.gerrit.extensions.common.ChangeInfo;
 import com.google.gerrit.extensions.common.RevisionInfo;
 import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.inject.ImplementedBy;
 import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.its.base.its.ItsConfig;
@@ -19,11 +20,9 @@
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class IssueExtractor {
-  private static final Logger log = LoggerFactory.getLogger(IssueExtractor.class);
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   private final CommitMessageFetcher commitMessageFetcher;
   private final PatchSetDb db;
@@ -47,7 +46,7 @@
       try {
         ChangeInfo info =
             gApi.changes()
-                .id(patchSetId.getParentKey().get())
+                .id(patchSetId.changeId().get())
                 .get(EnumSet.of(ListChangesOption.ALL_REVISIONS));
         for (Map.Entry<String, RevisionInfo> e : info.revisions.entrySet()) {
           if (e.getValue()._number == patchSetId.get()) {
@@ -80,7 +79,7 @@
     Pattern pattern = itsConfig.getIssuePattern();
     if (pattern == null) return new String[] {};
 
-    log.debug("Matching '{}' against {}", haystack, pattern.pattern());
+    logger.atFine().log("Matching '%s' against '%s'", haystack, pattern.pattern());
 
     Set<String> issues = Sets.newHashSet();
     Matcher matcher = pattern.matcher(haystack);
@@ -235,8 +234,7 @@
     if (patchSetId != null) {
       Map<String, Set<String>> previous = Maps.newHashMap();
       if (patchSetId.get() != 1) {
-        PatchSet.Id previousPatchSetId =
-            new PatchSet.Id(patchSetId.getParentKey(), patchSetId.get() - 1);
+        PatchSet.Id previousPatchSetId = PatchSet.id(patchSetId.changeId(), patchSetId.get() - 1);
         String previousPatchSet = db.getRevision(previousPatchSetId);
         if (previousPatchSet != null) {
           previous = getIssueIds(projectName, previousPatchSet);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/util/ItsProjectExtractor.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/util/ItsProjectExtractor.java
index 734582a..df7c3d9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/util/ItsProjectExtractor.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/util/ItsProjectExtractor.java
@@ -14,7 +14,7 @@
 
 package com.googlesource.gerrit.plugins.its.base.util;
 
-import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.entities.Project;
 import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.its.base.its.ItsConfig;
 import java.util.Optional;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/util/PropertyAttributeExtractor.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/util/PropertyAttributeExtractor.java
index f1b2c0d..d05e541 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/util/PropertyAttributeExtractor.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/util/PropertyAttributeExtractor.java
@@ -15,7 +15,7 @@
 package com.googlesource.gerrit.plugins.its.base.util;
 
 import com.google.common.collect.ImmutableMap;
-import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.entities.RefNames;
 import com.google.gerrit.server.data.AccountAttribute;
 import com.google.gerrit.server.data.ApprovalAttribute;
 import com.google.gerrit.server.data.ChangeAttribute;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractor.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractor.java
index 603a554..9d6b2d9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractor.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractor.java
@@ -14,9 +14,9 @@
 
 package com.googlesource.gerrit.plugins.its.base.util;
 
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.entities.PatchSet;
 import com.google.gerrit.extensions.annotations.PluginName;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.server.data.ApprovalAttribute;
 import com.google.gerrit.server.data.ChangeAttribute;
 import com.google.gerrit.server.data.PatchSetAttribute;
@@ -70,7 +70,7 @@
    */
   private PatchSet.Id newPatchSetId(String changeId, String patchId) {
     try {
-      return new PatchSet.Id(new Change.Id(Integer.parseInt(changeId)), Integer.parseInt(patchId));
+      return PatchSet.id(Change.id(Integer.parseInt(changeId)), Integer.parseInt(patchId));
     } catch (NumberFormatException e) {
       return null;
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/validation/ItsValidateComment.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/validation/ItsValidateComment.java
index b0c9e39..074b882 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/validation/ItsValidateComment.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/validation/ItsValidateComment.java
@@ -15,8 +15,9 @@
 package com.googlesource.gerrit.plugins.its.base.validation;
 
 import com.google.common.collect.Lists;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.Project;
 import com.google.gerrit.extensions.annotations.PluginName;
-import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.events.CommitReceivedEvent;
 import com.google.gerrit.server.git.validators.CommitValidationException;
 import com.google.gerrit.server.git.validators.CommitValidationListener;
@@ -30,12 +31,10 @@
 import java.util.Collections;
 import java.util.List;
 import org.eclipse.jgit.revwalk.RevCommit;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class ItsValidateComment implements CommitValidationListener {
 
-  private static final Logger log = LoggerFactory.getLogger(ItsValidateComment.class);
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   @Inject private ItsFacade client;
 
@@ -80,7 +79,7 @@
                   "Failed to check whether or not issue "
                       + issueId
                       + " exists, due to connectivity issue. Commit will be accepted.";
-              log.warn(synopsis, e);
+              logger.atWarning().withCause(e).log(synopsis);
               details = e.toString();
               existenceCheckResult = ItsExistenceCheckResult.CONNECTIVITY_FAILURE;
               ret.add(commitValidationFailure(synopsis, details, existenceCheckResult));
@@ -108,7 +107,8 @@
             sb.append(" Issue-Tracker");
             details = sb.toString();
 
-            ret.add(commitValidationFailure(synopsis, details, ItsExistenceCheckResult.DOESNT_EXIST));
+            ret.add(
+                commitValidationFailure(synopsis, details, ItsExistenceCheckResult.DOESNT_EXIST));
           }
         } else if (!itsConfig
             .getDummyIssuePattern()
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionController.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionController.java
index 4af8f1b..f9214c6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionController.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionController.java
@@ -14,6 +14,7 @@
 
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
+import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.server.events.Event;
 import com.google.gerrit.server.events.EventListener;
 import com.google.gerrit.server.events.RefEvent;
@@ -23,8 +24,6 @@
 import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Controller that takes actions according to {@code ChangeEvents@}.
@@ -34,7 +33,7 @@
  */
 public class ActionController implements EventListener {
 
-  private static final Logger log = LoggerFactory.getLogger(ActionController.class);
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   private final PropertyExtractor propertyExtractor;
   private final RuleBase ruleBase;
@@ -90,8 +89,8 @@
     }
     if (!projectProperties.containsKey("its-project")) {
       String project = projectProperties.get("project");
-      log.error(
-          "Could not process project event. No its-project associated with project {}. "
+      logger.atSevere().log(
+          "Could not process project event. No its-project associated with project %s. "
               + "Did you forget to configure the ITS project association in project.config?",
           project);
       return;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutor.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutor.java
index 33e82ae..3654e6f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutor.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutor.java
@@ -14,20 +14,19 @@
 
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.Project;
 import com.google.gerrit.extensions.registration.DynamicMap;
 import com.google.gerrit.extensions.registration.PluginName;
-import com.google.gerrit.reviewdb.client.Project;
 import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.its.base.its.ItsFacade;
 import com.googlesource.gerrit.plugins.its.base.its.ItsFacadeFactory;
 import java.io.IOException;
 import java.util.Map;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /** Executes an {@link ActionRequest} */
 public class ActionExecutor {
-  private static final Logger log = LoggerFactory.getLogger(ActionExecutor.class);
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   private final ItsFacadeFactory itsFactory;
   private final AddComment.Factory addCommentFactory;
@@ -95,7 +94,7 @@
         execute(action, issue, actionRequest, properties);
       }
     } catch (IOException e) {
-      log.error("Error while executing action " + actionRequest, e);
+      logger.atSevere().withCause(e).log("Error while executing action %s", actionRequest);
     }
   }
 
@@ -111,7 +110,7 @@
       String actionName = actionRequest.getName();
       Action action = getAction(actionName);
       if (action == null) {
-        log.debug("No action found for name {}", actionName);
+        logger.atFine().log("No action found for name %s", actionName);
         return;
       }
       if (action.getType() != ActionType.PROJECT) {
@@ -119,7 +118,7 @@
       }
       execute(action, itsProject, actionRequest, properties);
     } catch (IOException e) {
-      log.error("Error while executing action " + actionRequest, e);
+      logger.atSevere().withCause(e).log("Error while executing action %s", actionRequest);
     }
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/AddPropertyToFieldParametersExtractor.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/AddPropertyToFieldParametersExtractor.java
index 7a259f1..3b1f356 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/AddPropertyToFieldParametersExtractor.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/AddPropertyToFieldParametersExtractor.java
@@ -15,17 +15,14 @@
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
 import com.google.common.base.Strings;
+import com.google.common.flogger.FluentLogger;
 import com.google.inject.Inject;
 import java.util.Arrays;
 import java.util.Map;
 import java.util.Optional;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class AddPropertyToFieldParametersExtractor {
-
-  private static final Logger log =
-      LoggerFactory.getLogger(AddPropertyToFieldParametersExtractor.class);
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   @Inject
   public AddPropertyToFieldParametersExtractor() {}
@@ -38,26 +35,26 @@
       ActionRequest actionRequest, Map<String, String> properties) {
     String[] parameters = actionRequest.getParameters();
     if (parameters.length != 2) {
-      log.error(
-          "Wrong number of received parameters. Received parameters are {}. Exactly two parameters are expected. The first one is the ITS field id, the second one is the event property id",
+      logger.atSevere().log(
+          "Wrong number of received parameters. Received parameters are %s. Exactly two parameters are expected. The first one is the ITS field id, the second one is the event property id",
           Arrays.toString(parameters));
       return Optional.empty();
     }
 
     String propertyId = parameters[0];
     if (Strings.isNullOrEmpty(propertyId)) {
-      log.error("Received property id is blank");
+      logger.atSevere().log("Received property id is blank");
       return Optional.empty();
     }
 
     String fieldId = parameters[1];
     if (Strings.isNullOrEmpty(fieldId)) {
-      log.error("Received field id is blank");
+      logger.atSevere().log("Received field id is blank");
       return Optional.empty();
     }
 
     if (!properties.containsKey(propertyId)) {
-      log.error("No event property found for id {}", propertyId);
+      logger.atSevere().log("No event property found for id %s", propertyId);
       return Optional.empty();
     }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/AddSoyComment.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/AddSoyComment.java
index c29d622..d3f73a2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/AddSoyComment.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/AddSoyComment.java
@@ -15,13 +15,12 @@
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
 import com.google.common.base.Strings;
+import com.google.common.flogger.FluentLogger;
 import com.google.common.io.CharStreams;
 import com.google.inject.Inject;
 import com.google.inject.ProvisionException;
 import com.google.template.soy.SoyFileSet;
-import com.google.template.soy.SoyFileSet.Builder;
-import com.google.template.soy.data.SanitizedContent;
-import com.google.template.soy.tofu.SoyTofu;
+import com.google.template.soy.jbcsrc.api.SoySauce.Renderer;
 import com.googlesource.gerrit.plugins.its.base.ItsPath;
 import com.googlesource.gerrit.plugins.its.base.its.ItsFacade;
 import java.io.IOException;
@@ -31,8 +30,6 @@
 import java.nio.file.Path;
 import java.util.HashMap;
 import java.util.Map;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Adds a short predefined comments to an issue.
@@ -40,7 +37,7 @@
  * <p>Comments are added for merging, abandoning, restoring of changes and adding of patch sets.
  */
 public class AddSoyComment extends IssueAction {
-  private static final Logger log = LoggerFactory.getLogger(AddSoyComment.class);
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   public interface Factory {
     AddSoyComment create();
@@ -54,11 +51,9 @@
     this.templateDir = itsPath.resolve("templates");
   }
 
-  private String soyTemplate(
-      SoyFileSet.Builder builder,
-      String template,
-      SanitizedContent.ContentKind kind,
-      Map<String, String> properties) {
+  private String soyTextTemplate(
+      SoyFileSet.Builder builder, String template, Map<String, String> properties) {
+
     Path templatePath = templateDir.resolve(template + ".soy");
     String content;
 
@@ -70,18 +65,15 @@
     }
 
     builder.add(content, templatePath.toAbsolutePath().toString());
-    SoyTofu.Renderer renderer =
+    Renderer renderer =
         builder
             .build()
-            .compileToTofu()
-            .newRenderer("etc.its.templates." + template)
-            .setContentKind(kind)
+            .compileTemplates()
+            .renderTemplate("etc.its.templates." + template)
             .setData(properties);
-    return renderer.render();
-  }
-
-  private String soyTextTemplate(Builder builder, String template, Map<String, String> properties) {
-    return soyTemplate(builder, template, SanitizedContent.ContentKind.TEXT, properties);
+    String rendered = renderer.renderText().get();
+    logger.atFinest().log("Rendered template %s to:\n%s", templatePath, rendered);
+    return rendered;
   }
 
   @Override
@@ -96,10 +88,10 @@
 
   private String buildComment(ActionRequest actionRequest, Map<String, String> properties) {
     String template = actionRequest.getParameter(1);
-    if (!template.isEmpty()) {
+    if (!Strings.isNullOrEmpty(template)) {
       return soyTextTemplate(SoyFileSet.builder(), template, properties);
     }
-    log.error("No template name given in {}", actionRequest);
+    logger.atSevere().log("No template name given in %s", actionRequest);
     return "";
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/CreateVersionFromPropertyParametersExtractor.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/CreateVersionFromPropertyParametersExtractor.java
index 1eb01ce..3f81485 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/CreateVersionFromPropertyParametersExtractor.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/CreateVersionFromPropertyParametersExtractor.java
@@ -15,17 +15,14 @@
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
 import com.google.common.base.Strings;
+import com.google.common.flogger.FluentLogger;
 import java.util.Arrays;
 import java.util.Map;
 import java.util.Optional;
 import javax.inject.Inject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 class CreateVersionFromPropertyParametersExtractor {
-
-  private static final Logger log =
-      LoggerFactory.getLogger(CreateVersionFromPropertyParametersExtractor.class);
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   @Inject
   public CreateVersionFromPropertyParametersExtractor() {}
@@ -34,20 +31,20 @@
       ActionRequest actionRequest, Map<String, String> properties) {
     String[] parameters = actionRequest.getParameters();
     if (parameters.length != 1) {
-      log.error(
-          "Wrong number of received parameters. Received parameters are {}. Only one parameter is expected, the property id.",
+      logger.atSevere().log(
+          "Wrong number of received parameters. Received parameters are %s. Only one parameter is expected, the property id.",
           Arrays.toString(parameters));
       return Optional.empty();
     }
 
     String propertyId = parameters[0];
     if (Strings.isNullOrEmpty(propertyId)) {
-      log.error("Received property id is blank");
+      logger.atSevere().log("Received property id is blank");
       return Optional.empty();
     }
 
     if (!properties.containsKey(propertyId)) {
-      log.error("No event property found for id {}", propertyId);
+      logger.atSevere().log("No event property found for id %s", propertyId);
       return Optional.empty();
     }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheImpl.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheImpl.java
index 14307a0..9790f7d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheImpl.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheImpl.java
@@ -17,9 +17,10 @@
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableList;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.Project;
 import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
 import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.cache.CacheModule;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectState;
@@ -34,12 +35,10 @@
 import java.util.List;
 import java.util.concurrent.ExecutionException;
 import org.eclipse.jgit.lib.Config;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 @Singleton
 public class ItsRulesProjectCacheImpl implements ItsRulesProjectCache {
-  private static final Logger log = LoggerFactory.getLogger(ItsRulesProjectCacheImpl.class);
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
   private static final String CACHE_NAME = "its_rules_project";
 
   private final LoadingCache<String, List<Rule>> cache;
@@ -54,7 +53,8 @@
     try {
       return cache.get(projectName);
     } catch (ExecutionException e) {
-      log.warn("Cannot get project specific rules for project {}", projectName, e);
+      logger.atWarning().withCause(e).log(
+          "Cannot get project specific rules for project %s", projectName);
       return ImmutableList.of();
     }
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheRefresher.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheRefresher.java
index 4cbd3d2..75b91f7 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheRefresher.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheRefresher.java
@@ -1,16 +1,15 @@
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.RefNames;
 import com.google.gerrit.extensions.api.GerritApi;
 import com.google.gerrit.extensions.common.ProjectInfo;
 import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
 import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.inject.Inject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class ItsRulesProjectCacheRefresher implements GitReferenceUpdatedListener {
-  private static final Logger log = LoggerFactory.getLogger(ItsRulesProjectCacheRefresher.class);
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   private final GerritApi gApi;
   private final ItsRulesProjectCache itsRuleProjectCache;
@@ -33,7 +32,7 @@
         itsRuleProjectCache.evict(childProject.name);
       }
     } catch (RestApiException e) {
-      log.warn("Unable to evict ITS rules cache", e);
+      logger.atWarning().withCause(e).log("Unable to evict ITS rules cache");
     }
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/LogEvent.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/LogEvent.java
index 6eec9a4..f345227 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/LogEvent.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/LogEvent.java
@@ -14,13 +14,12 @@
 
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
+import com.google.common.flogger.FluentLogger;
 import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.its.base.its.ItsFacade;
 import java.io.IOException;
 import java.util.Map;
 import java.util.Map.Entry;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Dumps the event's properties to the log.
@@ -28,7 +27,7 @@
  * <p>This event helps when developing rules as available properties become visible.
  */
 public class LogEvent extends IssueAction {
-  private static final Logger log = LoggerFactory.getLogger(LogEvent.class);
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   private enum Level {
     ERROR,
@@ -56,23 +55,25 @@
   public LogEvent() {}
 
   private void logProperty(Level level, Entry<String, String> property) {
-    String message = String.format("[%s = %s]", property.getKey(), property.getValue());
+    final java.util.logging.Level logLevel;
     switch (level) {
       case ERROR:
-        log.error(message);
+        logLevel = java.util.logging.Level.SEVERE;
         break;
       case WARN:
-        log.warn(message);
+        logLevel = java.util.logging.Level.WARNING;
         break;
       case INFO:
-        log.info(message);
+        logLevel = java.util.logging.Level.INFO;
         break;
       case DEBUG:
-        log.debug(message);
+        logLevel = java.util.logging.Level.FINE;
         break;
       default:
-        log.error("Undefined log level.");
+        logger.atSevere().log("Undefined log level.");
+        return;
     }
+    logger.at(logLevel).log("[%s = %s]", property.getKey(), property.getValue());
   }
 
   @Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/RuleBase.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/RuleBase.java
index b6e4ad6..b051dfe 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/RuleBase.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/workflow/RuleBase.java
@@ -15,6 +15,7 @@
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.flogger.FluentLogger;
 import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.its.base.GlobalRulesFileName;
 import com.googlesource.gerrit.plugins.its.base.ItsPath;
@@ -29,12 +30,10 @@
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.util.FS;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /** Collection and matcher against {@link Rule}s. */
 public class RuleBase {
-  private static final Logger log = LoggerFactory.getLogger(RuleBase.class);
+  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   private final File globalRuleFile;
   private final File itsSpecificRuleFile;
@@ -81,7 +80,7 @@
         cfg.load();
         return rulesConfigReader.getRulesFromConfig(cfg);
       } catch (IOException | ConfigInvalidException e) {
-        log.error("Invalid ITS action configuration", e);
+        logger.atSevere().withCause(e).log("Invalid ITS action configuration");
       }
     }
     return Collections.emptyList();
@@ -98,12 +97,10 @@
     Collection<Rule> fromProjectConfig = rulesProjectCache.get(projectName);
     Collection<Rule> rulesToAdd = !fromProjectConfig.isEmpty() ? fromProjectConfig : rules;
     if (rulesToAdd.isEmpty() && !globalRuleFile.exists() && !itsSpecificRuleFile.exists()) {
-      log.warn(
-          "Neither global rule file {} nor Its specific rule file {} exist and no rules are "
-              + "configured for project {}. Please configure rules.",
-          globalRuleFile,
-          itsSpecificRuleFile,
-          projectName);
+      logger.atFine().log(
+          "Neither global rule file %s nor Its specific rule file %s exist and no rules are "
+              + "configured for project %s. Please configure rules.",
+          globalRuleFile, itsSpecificRuleFile, projectName);
       return Collections.emptyList();
     }
     Collection<ActionRequest> actions = new ArrayList<>();
diff --git a/src/main/resources/Documentation/config-rulebase-common.md b/src/main/resources/Documentation/config-rulebase-common.md
index 1220751..e877e9b 100644
--- a/src/main/resources/Documentation/config-rulebase-common.md
+++ b/src/main/resources/Documentation/config-rulebase-common.md
@@ -651,12 +651,9 @@
 
 ```
 {namespace etc.its.templates}
-
-/**
- * @param changeNumber
- * @param formatChangeUrl
- */
-{template .TemplateName autoescape="strict" kind="text"}
+{template .TemplateName kind="text"}
+  {@param changeNumber: string}
+  {@param formatChangeUrl: string}
   inline Comment for change {$changeNumber} added. See {$formatChangeUrl}
 {/template}
 ```
diff --git a/src/main/templates/Documentation/build.md b/src/main/templates/Documentation/build.md
index 6dd56fa..9e12cb5 100644
--- a/src/main/templates/Documentation/build.md
+++ b/src/main/templates/Documentation/build.md
@@ -16,7 +16,7 @@
 The output is created in
 
 ```
-  bazel-genfiles/its-base.jar
+  bazel-bin/its-base.jar
 ```
 
 To execute the tests run:
@@ -52,7 +52,7 @@
 The output is created in
 
 ```
-  bazel-genfiles/plugins/its-base/its-base.jar
+  bazel-bin/plugins/its-base/its-base.jar
 ```
 
 This project can be imported into the Eclipse IDE:
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfigTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfigTest.java
index 1a147c7..3379908 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfigTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfigTest.java
@@ -14,13 +14,16 @@
 
 package com.googlesource.gerrit.plugins.its.base.its;
 
-import static org.easymock.EasyMock.eq;
-import static org.easymock.EasyMock.expect;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import com.google.common.base.Suppliers;
+import com.google.gerrit.entities.Project;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.config.FactoryModule;
-import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.PluginConfig;
 import com.google.gerrit.server.config.PluginConfigFactory;
@@ -51,59 +54,53 @@
 
   public void setupIsEnabled(
       String enabled, String itsProject, String parentEnabled, String[] branches) {
-    ProjectState projectState = createMock(ProjectState.class);
+    ProjectState projectState = mock(ProjectState.class);
 
-    expect(projectCache.get(new Project.NameKey("testProject"))).andReturn(projectState).anyTimes();
-    expect(projectCache.get(new Project.NameKey("parentProject")))
-        .andReturn(projectState)
-        .anyTimes();
+    when(projectCache.get(Project.nameKey("testProject"))).thenReturn(projectState);
+    when(projectCache.get(Project.nameKey("parentProject"))).thenReturn(projectState);
 
     Iterable<ProjectState> parents;
     if (parentEnabled == null) {
       parents = Arrays.asList(projectState);
     } else {
-      ProjectState parentProjectState = createMock(ProjectState.class);
+      ProjectState parentProjectState = mock(ProjectState.class);
 
-      PluginConfig parentPluginConfig = createMock(PluginConfig.class);
+      PluginConfig parentPluginConfig = mock(PluginConfig.class);
 
-      expect(pluginConfigFactory.getFromProjectConfig(parentProjectState, "ItsTestName"))
-          .andReturn(parentPluginConfig);
+      when(pluginConfigFactory.getFromProjectConfig(parentProjectState, "ItsTestName"))
+          .thenReturn(parentPluginConfig);
 
-      expect(parentPluginConfig.getString("enabled", "false")).andReturn(parentEnabled).anyTimes();
+      when(parentPluginConfig.getString("enabled", "false")).thenReturn(parentEnabled);
 
-      PluginConfig parentPluginConfigWI = createMock(PluginConfig.class);
+      PluginConfig parentPluginConfigWI = mock(PluginConfig.class);
 
-      expect(
-              pluginConfigFactory.getFromProjectConfigWithInheritance(
-                  parentProjectState, "ItsTestName"))
-          .andReturn(parentPluginConfigWI)
-          .anyTimes();
+      when(pluginConfigFactory.getFromProjectConfigWithInheritance(
+              parentProjectState, "ItsTestName"))
+          .thenReturn(parentPluginConfigWI);
 
       String[] parentBranches = {"refs/heads/testBranch"};
-      expect(parentPluginConfigWI.getStringList("branch")).andReturn(parentBranches).anyTimes();
+      when(parentPluginConfigWI.getStringList("branch")).thenReturn(parentBranches);
 
       parents = Arrays.asList(parentProjectState, projectState);
     }
-    expect(projectState.treeInOrder()).andReturn(parents).anyTimes();
+    when(projectState.treeInOrder()).thenReturn(parents);
 
-    PluginConfig pluginConfig = createMock(PluginConfig.class);
+    PluginConfig pluginConfig = mock(PluginConfig.class);
 
-    expect(pluginConfigFactory.getFromProjectConfig(projectState, "ItsTestName"))
-        .andReturn(pluginConfig)
-        .anyTimes();
+    when(pluginConfigFactory.getFromProjectConfig(projectState, "ItsTestName"))
+        .thenReturn(pluginConfig);
 
-    expect(pluginConfig.getString("enabled", "false")).andReturn(enabled).anyTimes();
-    expect(pluginConfig.getString(eq("its-project"))).andReturn(itsProject).anyTimes();
+    when(pluginConfig.getString("enabled", "false")).thenReturn(enabled);
+    when(pluginConfig.getString(eq("its-project"))).thenReturn(itsProject);
 
-    PluginConfig pluginConfigWI = createMock(PluginConfig.class);
+    PluginConfig pluginConfigWI = mock(PluginConfig.class);
 
-    expect(pluginConfigFactory.getFromProjectConfigWithInheritance(projectState, "ItsTestName"))
-        .andReturn(pluginConfigWI)
-        .anyTimes();
+    when(pluginConfigFactory.getFromProjectConfigWithInheritance(projectState, "ItsTestName"))
+        .thenReturn(pluginConfigWI);
 
-    expect(pluginConfigWI.getString("enabled", "false")).andReturn(enabled).anyTimes();
+    when(pluginConfigWI.getString("enabled", "false")).thenReturn(enabled);
 
-    expect(pluginConfigWI.getStringList("branch")).andReturn(branches).anyTimes();
+    when(pluginConfigWI.getStringList("branch")).thenReturn(branches);
   }
 
   public void testIsEnabledRefNoParentNoBranchEnabled() {
@@ -112,9 +109,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertTrue(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -124,9 +119,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertFalse(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -136,9 +129,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertTrue(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -148,9 +139,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertTrue(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -160,9 +149,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertFalse(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -172,9 +159,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertTrue(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -184,9 +169,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertFalse(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -196,9 +179,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertFalse(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -208,9 +189,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertFalse(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -220,9 +199,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertTrue(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -232,9 +209,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertFalse(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -244,9 +219,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertTrue(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -256,9 +229,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertFalse(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -268,9 +239,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertFalse(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -280,9 +249,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Project.NameKey projectNK = new Project.NameKey("testProject");
+    Project.NameKey projectNK = Project.nameKey("testProject");
     assertTrue(itsConfig.isEnabled(projectNK, "refs/heads/testBranch"));
   }
 
@@ -294,8 +261,6 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertTrue(itsConfig.isEnabled(event));
   }
 
@@ -307,8 +272,6 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertTrue(itsConfig.isEnabled(event));
   }
 
@@ -320,8 +283,6 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertTrue(itsConfig.isEnabled(event));
   }
 
@@ -333,8 +294,6 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertFalse(itsConfig.isEnabled(event));
   }
 
@@ -346,8 +305,6 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertTrue(itsConfig.isEnabled(event));
   }
 
@@ -359,8 +316,6 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertTrue(itsConfig.isEnabled(event));
   }
 
@@ -372,8 +327,6 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertTrue(itsConfig.isEnabled(event));
   }
 
@@ -385,8 +338,6 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertTrue(itsConfig.isEnabled(event));
   }
 
@@ -398,8 +349,6 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertFalse(itsConfig.isEnabled(event));
   }
 
@@ -411,8 +360,6 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertTrue(itsConfig.isEnabled(event));
   }
 
@@ -424,8 +371,6 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertTrue(itsConfig.isEnabled(event));
   }
 
@@ -437,8 +382,6 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertTrue(itsConfig.isEnabled(event));
   }
 
@@ -450,8 +393,6 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertTrue(itsConfig.isEnabled(event));
   }
 
@@ -467,18 +408,14 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertTrue(itsConfig.isEnabled(event));
   }
 
   public void BROKEN_testIsEnabledUnknownEvent() {
-    RefEvent event = createMock(RefEvent.class);
+    RefEvent event = mock(RefEvent.class);
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
     assertFalse(itsConfig.isEnabled(event));
     assertLogMessageContains("not recognised and ignored");
   }
@@ -489,9 +426,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    assertFalse(itsConfig.getItsProjectName(new Project.NameKey("testProject")).isPresent());
+    assertFalse(itsConfig.getItsProjectName(Project.nameKey("testProject")).isPresent());
   }
 
   public void testGetItsProjectConfigured() {
@@ -500,10 +435,7 @@
 
     ItsConfig itsConfig = createItsConfig();
 
-    replayMocks();
-
-    Optional<String> itsProjectName =
-        itsConfig.getItsProjectName(new Project.NameKey("testProject"));
+    Optional<String> itsProjectName = itsConfig.getItsProjectName(Project.nameKey("testProject"));
     assertTrue(itsProjectName.isPresent());
     assertEquals("itsProject", itsProjectName.get());
   }
@@ -511,328 +443,280 @@
   public void testGetIssuePatternNullMatch() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn(null)
-        .atLeastOnce();
-    expect(serverConfig.getString("commentlink", "ItsTestName", "match"))
-        .andReturn(null)
-        .atLeastOnce();
-
-    replayMocks();
-
     assertNull("Pattern for null match is not null", itsConfig.getIssuePattern());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig).getString("commentlink", "ItsTestName", "match");
   }
 
   public void testGetIssuePatternNullMatchWCommentLink() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn("foo")
-        .atLeastOnce();
-    expect(serverConfig.getString("commentlink", "foo", "match")).andReturn(null).atLeastOnce();
-
-    replayMocks();
+    when(serverConfig.getString("plugin", "ItsTestName", "commentlink")).thenReturn("foo");
 
     assertNull("Pattern for null match is not null", itsConfig.getIssuePattern());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig).getString("commentlink", "foo", "match");
   }
 
   public void testGetIssuePattern() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn(null)
-        .atLeastOnce();
-    expect(serverConfig.getString("commentlink", "ItsTestName", "match"))
-        .andReturn("TestPattern")
-        .atLeastOnce();
-
-    replayMocks();
+    when(serverConfig.getString("commentlink", "ItsTestName", "match")).thenReturn("TestPattern");
 
     assertEquals(
         "Expected and generated pattern are not equal",
         "TestPattern",
         itsConfig.getIssuePattern().pattern());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig).getString("commentlink", "ItsTestName", "match");
   }
 
   public void testGetIssuePatternWCommentLink() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn("foo")
-        .atLeastOnce();
-    expect(serverConfig.getString("commentlink", "foo", "match"))
-        .andReturn("TestPattern")
-        .atLeastOnce();
-
-    replayMocks();
+    when(serverConfig.getString("plugin", "ItsTestName", "commentlink")).thenReturn("foo");
+    when(serverConfig.getString("commentlink", "foo", "match")).thenReturn("TestPattern");
 
     assertEquals(
         "Expected and generated pattern are not equal",
         "TestPattern",
         itsConfig.getIssuePattern().pattern());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig).getString("commentlink", "foo", "match");
   }
 
   public void testGetIssuePatternGroupIndexGroupDefault() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn(null)
-        .atLeastOnce();
-    expect(serverConfig.getString("commentlink", "ItsTestName", "match"))
-        .andReturn("(foo)(bar)(baz)")
-        .atLeastOnce();
-    expect(serverConfig.getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1))
-        .andReturn(1)
-        .atLeastOnce();
-
-    replayMocks();
+    when(serverConfig.getString("commentlink", "ItsTestName", "match"))
+        .thenReturn("(foo)(bar)(baz)");
+    when(serverConfig.getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1)).thenReturn(1);
 
     assertEquals(
         "Expected and actual group index do not match", 1, itsConfig.getIssuePatternGroupIndex());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig).getString("commentlink", "ItsTestName", "match");
+    verifyOneOrMore(serverConfig).getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1);
   }
 
   public void testGetIssuePatternGroupIndexGroupDefaultGroupless() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn(null)
-        .atLeastOnce();
-    expect(serverConfig.getString("commentlink", "ItsTestName", "match"))
-        .andReturn("foo")
-        .atLeastOnce();
-    expect(serverConfig.getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1))
-        .andReturn(1)
-        .atLeastOnce();
-
-    replayMocks();
+    when(serverConfig.getString("commentlink", "ItsTestName", "match")).thenReturn("foo");
+    when(serverConfig.getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1)).thenReturn(1);
 
     assertEquals(
         "Expected and actual group index do not match", 0, itsConfig.getIssuePatternGroupIndex());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig).getString("commentlink", "ItsTestName", "match");
+    verifyOneOrMore(serverConfig).getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1);
   }
 
   public void testGetIssuePatternGroupIndexGroup1() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn(null)
-        .atLeastOnce();
-    expect(serverConfig.getString("commentlink", "ItsTestName", "match"))
-        .andReturn("(foo)(bar)(baz)")
-        .atLeastOnce();
-    expect(serverConfig.getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1))
-        .andReturn(1)
-        .atLeastOnce();
-
-    replayMocks();
+    when(serverConfig.getString("commentlink", "ItsTestName", "match"))
+        .thenReturn("(foo)(bar)(baz)");
+    when(serverConfig.getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1)).thenReturn(1);
 
     assertEquals(
         "Expected and actual group index do not match", 1, itsConfig.getIssuePatternGroupIndex());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig).getString("commentlink", "ItsTestName", "match");
+    verifyOneOrMore(serverConfig).getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1);
   }
 
   public void testGetIssuePatternGroupIndexGroup3() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn(null)
-        .atLeastOnce();
-    expect(serverConfig.getString("commentlink", "ItsTestName", "match"))
-        .andReturn("(foo)(bar)(baz)")
-        .atLeastOnce();
-    expect(serverConfig.getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1))
-        .andReturn(3)
-        .atLeastOnce();
-
-    replayMocks();
+    when(serverConfig.getString("commentlink", "ItsTestName", "match"))
+        .thenReturn("(foo)(bar)(baz)");
+    when(serverConfig.getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1)).thenReturn(3);
 
     assertEquals(
         "Expected and actual group index do not match", 3, itsConfig.getIssuePatternGroupIndex());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig).getString("commentlink", "ItsTestName", "match");
+    verifyOneOrMore(serverConfig).getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1);
   }
 
   public void testGetIssuePatternGroupIndexGroupTooHigh() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn(null)
-        .atLeastOnce();
-    expect(serverConfig.getString("commentlink", "ItsTestName", "match"))
-        .andReturn("(foo)(bar)(baz)")
-        .atLeastOnce();
-    expect(serverConfig.getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1))
-        .andReturn(5)
-        .atLeastOnce();
-
-    replayMocks();
+    when(serverConfig.getString("commentlink", "ItsTestName", "match"))
+        .thenReturn("(foo)(bar)(baz)");
+    when(serverConfig.getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1)).thenReturn(5);
 
     assertEquals(
         "Expected and actual group index do not match", 1, itsConfig.getIssuePatternGroupIndex());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig).getString("commentlink", "ItsTestName", "match");
+    verifyOneOrMore(serverConfig).getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1);
   }
 
   public void testGetIssuePatternGroupIndexGroupTooHighGroupless() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn(null)
-        .atLeastOnce();
-    expect(serverConfig.getString("commentlink", "ItsTestName", "match"))
-        .andReturn("foo")
-        .atLeastOnce();
-    expect(serverConfig.getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1))
-        .andReturn(5)
-        .atLeastOnce();
-
-    replayMocks();
+    when(serverConfig.getString("commentlink", "ItsTestName", "match")).thenReturn("foo");
+    when(serverConfig.getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1)).thenReturn(5);
 
     assertEquals(
         "Expected and actual group index do not match", 0, itsConfig.getIssuePatternGroupIndex());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig).getString("commentlink", "ItsTestName", "match");
+    verifyOneOrMore(serverConfig).getInt("plugin", "ItsTestName", "commentlinkGroupIndex", 1);
   }
 
   public void testGetItsAssociationPolicyOptional() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn(null)
-        .atLeastOnce();
-    expect(
-            serverConfig.getEnum(
-                "commentlink", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL))
-        .andReturn(ItsAssociationPolicy.OPTIONAL)
-        .atLeastOnce();
-    expect(
-            serverConfig.getEnum(
-                "plugin", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL))
-        .andReturn(ItsAssociationPolicy.OPTIONAL)
-        .atLeastOnce();
-
-    replayMocks();
+    when(serverConfig.getEnum(
+            "commentlink", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL))
+        .thenReturn(ItsAssociationPolicy.OPTIONAL);
+    when(serverConfig.getEnum(
+            "plugin", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL))
+        .thenReturn(ItsAssociationPolicy.OPTIONAL);
 
     assertEquals(
         "Expected and generated associated policy do not match",
         ItsAssociationPolicy.OPTIONAL,
         itsConfig.getItsAssociationPolicy());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig)
+        .getEnum("commentlink", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL);
+    verifyOneOrMore(serverConfig)
+        .getEnum("plugin", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL);
   }
 
   public void testGetItsAssociationPolicyOptionalWCommentLink() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn("foo")
-        .atLeastOnce();
-    expect(serverConfig.getEnum("commentlink", "foo", "association", ItsAssociationPolicy.OPTIONAL))
-        .andReturn(ItsAssociationPolicy.OPTIONAL)
-        .atLeastOnce();
-    expect(
-            serverConfig.getEnum(
-                "plugin", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL))
-        .andReturn(ItsAssociationPolicy.OPTIONAL)
-        .atLeastOnce();
-
-    replayMocks();
+    when(serverConfig.getString("plugin", "ItsTestName", "commentlink")).thenReturn("foo");
+    when(serverConfig.getEnum("commentlink", "foo", "association", ItsAssociationPolicy.OPTIONAL))
+        .thenReturn(ItsAssociationPolicy.OPTIONAL);
+    when(serverConfig.getEnum(
+            "plugin", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL))
+        .thenReturn(ItsAssociationPolicy.OPTIONAL);
 
     assertEquals(
         "Expected and generated associated policy do not match",
         ItsAssociationPolicy.OPTIONAL,
         itsConfig.getItsAssociationPolicy());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig)
+        .getEnum("commentlink", "foo", "association", ItsAssociationPolicy.OPTIONAL);
+    verifyOneOrMore(serverConfig)
+        .getEnum("plugin", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL);
   }
 
   public void testGetItsAssociationPolicySuggested() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn(null)
-        .atLeastOnce();
-    expect(
-            serverConfig.getEnum(
-                "commentlink", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL))
-        .andReturn(ItsAssociationPolicy.SUGGESTED)
-        .atLeastOnce();
-    expect(
-            serverConfig.getEnum(
-                "plugin", "ItsTestName", "association", ItsAssociationPolicy.SUGGESTED))
-        .andReturn(ItsAssociationPolicy.SUGGESTED)
-        .atLeastOnce();
-    replayMocks();
+    when(serverConfig.getEnum(
+            "commentlink", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL))
+        .thenReturn(ItsAssociationPolicy.SUGGESTED);
+    when(serverConfig.getEnum(
+            "plugin", "ItsTestName", "association", ItsAssociationPolicy.SUGGESTED))
+        .thenReturn(ItsAssociationPolicy.SUGGESTED);
 
     assertEquals(
         "Expected and generated associated policy do not match",
         ItsAssociationPolicy.SUGGESTED,
         itsConfig.getItsAssociationPolicy());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig)
+        .getEnum("commentlink", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL);
+    verifyOneOrMore(serverConfig)
+        .getEnum("plugin", "ItsTestName", "association", ItsAssociationPolicy.SUGGESTED);
   }
 
   public void testGetItsAssociationPolicySuggestedWCommentLink() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn("foo")
-        .atLeastOnce();
-    expect(
-            serverConfig.getEnum(
-                "plugin", "ItsTestName", "association", ItsAssociationPolicy.SUGGESTED))
-        .andReturn(ItsAssociationPolicy.SUGGESTED)
-        .atLeastOnce();
-    expect(serverConfig.getEnum("commentlink", "foo", "association", ItsAssociationPolicy.OPTIONAL))
-        .andReturn(ItsAssociationPolicy.SUGGESTED)
-        .atLeastOnce();
-
-    replayMocks();
+    when(serverConfig.getString("plugin", "ItsTestName", "commentlink")).thenReturn("foo");
+    when(serverConfig.getEnum(
+            "plugin", "ItsTestName", "association", ItsAssociationPolicy.SUGGESTED))
+        .thenReturn(ItsAssociationPolicy.SUGGESTED);
+    when(serverConfig.getEnum("commentlink", "foo", "association", ItsAssociationPolicy.OPTIONAL))
+        .thenReturn(ItsAssociationPolicy.SUGGESTED);
 
     assertEquals(
         "Expected and generated associated policy do not match",
         ItsAssociationPolicy.SUGGESTED,
         itsConfig.getItsAssociationPolicy());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig)
+        .getEnum("plugin", "ItsTestName", "association", ItsAssociationPolicy.SUGGESTED);
+    verifyOneOrMore(serverConfig)
+        .getEnum("commentlink", "foo", "association", ItsAssociationPolicy.OPTIONAL);
   }
 
   public void testGetItsAssociationPolicyMandatory() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn(null)
-        .atLeastOnce();
-    expect(
-            serverConfig.getEnum(
-                "commentlink", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL))
-        .andReturn(ItsAssociationPolicy.MANDATORY)
-        .atLeastOnce();
-    expect(
-            serverConfig.getEnum(
-                "plugin", "ItsTestName", "association", ItsAssociationPolicy.MANDATORY))
-        .andReturn(ItsAssociationPolicy.MANDATORY)
-        .atLeastOnce();
-
-    replayMocks();
+    when(serverConfig.getEnum(
+            "commentlink", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL))
+        .thenReturn(ItsAssociationPolicy.MANDATORY);
+    when(serverConfig.getEnum(
+            "plugin", "ItsTestName", "association", ItsAssociationPolicy.MANDATORY))
+        .thenReturn(ItsAssociationPolicy.MANDATORY);
 
     assertEquals(
         "Expected and generated associated policy do not match",
         ItsAssociationPolicy.MANDATORY,
         itsConfig.getItsAssociationPolicy());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig)
+        .getEnum("commentlink", "ItsTestName", "association", ItsAssociationPolicy.OPTIONAL);
+    verifyOneOrMore(serverConfig)
+        .getEnum("plugin", "ItsTestName", "association", ItsAssociationPolicy.MANDATORY);
   }
 
   public void testGetItsAssociationPolicyMandatoryWCommentLink() {
     ItsConfig itsConfig = createItsConfig();
 
-    expect(serverConfig.getString("plugin", "ItsTestName", "commentlink"))
-        .andReturn("foo")
-        .atLeastOnce();
-    expect(serverConfig.getEnum("commentlink", "foo", "association", ItsAssociationPolicy.OPTIONAL))
-        .andReturn(ItsAssociationPolicy.MANDATORY)
-        .atLeastOnce();
-    expect(
-            serverConfig.getEnum(
-                "plugin", "ItsTestName", "association", ItsAssociationPolicy.MANDATORY))
-        .andReturn(ItsAssociationPolicy.MANDATORY)
-        .atLeastOnce();
-
-    replayMocks();
+    when(serverConfig.getString("plugin", "ItsTestName", "commentlink")).thenReturn("foo");
+    when(serverConfig.getEnum("commentlink", "foo", "association", ItsAssociationPolicy.OPTIONAL))
+        .thenReturn(ItsAssociationPolicy.MANDATORY);
+    when(serverConfig.getEnum(
+            "plugin", "ItsTestName", "association", ItsAssociationPolicy.MANDATORY))
+        .thenReturn(ItsAssociationPolicy.MANDATORY);
 
     assertEquals(
         "Expected and generated associated policy do not match",
         ItsAssociationPolicy.MANDATORY,
         itsConfig.getItsAssociationPolicy());
+
+    verifyOneOrMore(serverConfig).getString("plugin", "ItsTestName", "commentlink");
+    verifyOneOrMore(serverConfig)
+        .getEnum("commentlink", "foo", "association", ItsAssociationPolicy.OPTIONAL);
+    verifyOneOrMore(serverConfig)
+        .getEnum("plugin", "ItsTestName", "association", ItsAssociationPolicy.MANDATORY);
   }
 
   private ItsConfig createItsConfig() {
     return injector.getInstance(ItsConfig.class);
   }
 
+  private <T> T verifyOneOrMore(T mock) {
+    return verify(mock, atLeastOnce());
+  }
+
   @Override
   public void setUp() throws Exception {
     super.setUp();
@@ -842,15 +726,15 @@
   private class TestModule extends FactoryModule {
     @Override
     protected void configure() {
-      projectCache = createMock(ProjectCache.class);
+      projectCache = mock(ProjectCache.class);
       bind(ProjectCache.class).toInstance(projectCache);
 
-      pluginConfigFactory = createMock(PluginConfigFactory.class);
+      pluginConfigFactory = mock(PluginConfigFactory.class);
       bind(PluginConfigFactory.class).toInstance(pluginConfigFactory);
 
       bind(String.class).annotatedWith(PluginName.class).toInstance("ItsTestName");
 
-      serverConfig = createMock(Config.class);
+      serverConfig = mock(Config.class);
       bind(Config.class).annotatedWith(GerritServerConfig.class).toInstance(serverConfig);
     }
   }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/LoggingMockingTestCase.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/LoggingMockingTestCase.java
index b1d98e2..8ca3d5b 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/LoggingMockingTestCase.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/LoggingMockingTestCase.java
@@ -14,82 +14,113 @@
 
 package com.googlesource.gerrit.plugins.its.base.testutil;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import com.google.common.collect.Lists;
-import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.Branch;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.entities.Account;
+import com.google.gerrit.entities.BranchNameKey;
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.entities.Project;
 import com.googlesource.gerrit.plugins.its.base.testutil.log.LogUtil;
 import java.sql.Timestamp;
 import java.util.Iterator;
+import java.util.logging.LogRecord;
+import junit.framework.TestCase;
 import org.apache.log4j.Level;
-import org.apache.log4j.spi.LoggingEvent;
 import org.junit.After;
 
-public abstract class LoggingMockingTestCase extends MockingTestCase {
+public abstract class LoggingMockingTestCase extends TestCase {
 
   protected final Change.Key testChangeKey =
-      new Change.Key("Ic19f7bf6c8b4685c363a8204c32d827ffda52ec0");
-  protected final Change.Id testChangeId = new Change.Id(1);
-  protected final Account.Id testAccountId = new Account.Id(1);
+      Change.key("Ic19f7bf6c8b4685c363a8204c32d827ffda52ec0");
+  protected final Change.Id testChangeId = Change.id(1);
+  protected final Account.Id testAccountId = Account.id(1);
 
-  private java.util.Collection<LoggingEvent> loggedEvents;
+  private java.util.Collection<LogRecord> records;
 
-  protected final void assertLogMessageContains(String needle, Level level) {
-    LoggingEvent hit = null;
-    Iterator<LoggingEvent> iter = loggedEvents.iterator();
-    while (hit == null && iter.hasNext()) {
-      LoggingEvent event = iter.next();
-      if (event.getRenderedMessage().contains(needle)) {
-        if (level == null || level.equals(event.getLevel())) {
-          hit = event;
+  protected final void assertLogMessageContains(String needle, Level level, int times) {
+    // We do not support `times == 0`, as it's ambiguous if it means the message does not occur at
+    // all, or message assertion should be skipped.
+    assertThat(times).isGreaterThan(0);
+
+    while (times-- > 0) {
+      LogRecord hit = null;
+      Iterator<LogRecord> iter = records.iterator();
+      while (hit == null && iter.hasNext()) {
+        LogRecord record = iter.next();
+        if (record.getMessage().contains(needle)) {
+          if (level == null || LogUtil.equalLevels(record.getLevel(), level)) {
+            hit = record;
+          }
         }
       }
+      removeLogHit(hit, "containing '" + needle + "'");
     }
-    assertNotNull("Could not find log message containing '" + needle + "'", hit);
-    assertTrue(
-        "Could not remove log message containing '" + needle + "'", loggedEvents.remove(hit));
+  }
+
+  protected final void assertLogMessageContains(String needle, Level level) {
+    assertLogMessageContains(needle, level, 1);
   }
 
   protected final void assertLogMessageContains(String needle) {
     assertLogMessageContains(needle, null);
   }
 
-  protected final void assertLogThrowableMessageContains(String needle) {
-    LoggingEvent hit = null;
-    Iterator<LoggingEvent> iter = loggedEvents.iterator();
-    while (hit == null && iter.hasNext()) {
-      LoggingEvent event = iter.next();
+  protected final void assertLogMessageContains(String needle, int times) {
+    assertLogMessageContains(needle, null, times);
+  }
 
-      if (event.getThrowableInformation().getThrowable().toString().contains(needle)) {
-        hit = event;
+  protected final void assertLogThrowableMessageContains(String needle) {
+    LogRecord hit = null;
+    Iterator<LogRecord> iter = records.iterator();
+    while (hit == null && iter.hasNext()) {
+      LogRecord record = iter.next();
+
+      Throwable t = record.getThrown();
+      if (t != null && t.toString().contains(needle)) {
+        hit = record;
       }
     }
-    assertNotNull("Could not find log message with a Throwable containing '" + needle + "'", hit);
-    assertTrue(
-        "Could not remove log message with a Throwable containing '" + needle + "'",
-        loggedEvents.remove(hit));
+    removeLogHit(hit, "with a Throwable containing '\" + needle + \"'");
+  }
+
+  private void removeLogHit(LogRecord hit, String description) {
+    if (hit == null) {
+      failWithUnassertedLogDump("Could not find log message " + description);
+    }
+    assertTrue("Could not remove log message " + description, records.remove(hit));
   }
 
   // As the PowerMock runner does not pass through runTest, we inject log
   // verification through @After
   @After
   public final void assertNoUnassertedLogEvents() {
-    if (loggedEvents.size() > 0) {
-      LoggingEvent event = loggedEvents.iterator().next();
-      String msg = "Found untreated logged events. First one is:\n";
-      msg += event.getRenderedMessage();
-      if (event.getThrowableInformation() != null) {
-        msg += "\n" + event.getThrowableInformation().getThrowable();
-      }
-      fail(msg);
+    if (records.size() > 0) {
+      failWithUnassertedLogDump("Found unasserted logged events.");
     }
   }
 
+  public final void failWithUnassertedLogDump(String msg) {
+    msg += "\n";
+    if (records.size() == 0) {
+      msg += "(All logged messages have already been asserted)";
+    } else {
+      msg += records.size() + " logged, but not yet asserted messages remain:";
+      for (LogRecord record : records) {
+        msg += "\n" + record.getMessage();
+        Throwable t = record.getThrown();
+        if (t != null) {
+          msg += "\n   with thrown " + t;
+        }
+      }
+    }
+    fail(msg);
+  }
+
   @Override
   public void setUp() throws Exception {
     super.setUp();
-    loggedEvents = Lists.newArrayList();
+    records = Lists.newArrayList();
 
     // The logger we're interested is class name without the trailing "Test".
     // While this is not the most general approach it is sufficient for now,
@@ -97,7 +128,7 @@
     // to check.
     String logName = this.getClass().getCanonicalName();
     logName = logName.substring(0, logName.length() - 4);
-    LogUtil.logToCollection(logName, loggedEvents);
+    LogUtil.logToCollection(logName, records, Level.DEBUG);
   }
 
   @Override
@@ -115,7 +146,7 @@
         testChangeKey,
         testChangeId,
         testAccountId,
-        new Branch.NameKey(new Project.NameKey(project), branch),
+        BranchNameKey.create(Project.nameKey(project), branch),
         new Timestamp(System.currentTimeMillis()));
   }
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/MockingTestCase.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/MockingTestCase.java
deleted file mode 100644
index d717024..0000000
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/MockingTestCase.java
+++ /dev/null
@@ -1,157 +0,0 @@
-// Copyright (C) 2013 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.googlesource.gerrit.plugins.its.base.testutil;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import junit.framework.TestCase;
-import org.easymock.Capture;
-import org.easymock.EasyMock;
-import org.easymock.IMocksControl;
-import org.junit.After;
-import org.junit.runner.RunWith;
-import org.powermock.api.easymock.PowerMock;
-import org.powermock.modules.junit4.PowerMockRunner;
-
-/** Test case with some support for automatically verifying mocks. */
-public abstract class MockingTestCase extends TestCase {
-  private Collection<Object> mocks;
-  private Collection<IMocksControl> mockControls;
-  private boolean mocksReplayed;
-  private boolean usePowerMock;
-
-  /**
-   * Create and register a mock control.
-   *
-   * @return The mock control instance.
-   */
-  protected final IMocksControl createMockControl() {
-    IMocksControl mockControl = EasyMock.createControl();
-    assertTrue("Adding mock control failed", mockControls.add(mockControl));
-    return mockControl;
-  }
-
-  /**
-   * Create and register a mock.
-   *
-   * <p>Creates a mock and registers it in the list of created mocks, so it gets treated
-   * automatically upon {@code replay} and {@code verify};
-   *
-   * @param toMock The class to create a mock for.
-   * @return The mock instance.
-   */
-  protected final <T> T createMock(Class<T> toMock) {
-    return createMock(toMock, null);
-  }
-
-  /**
-   * Create a mock for a mock control and register a mock.
-   *
-   * <p>Creates a mock and registers it in the list of created mocks, so it gets treated
-   * automatically upon {@code replay} and {@code verify};
-   *
-   * @param toMock The class to create a mock for.
-   * @param control The mock control to create the mock on. If null, do not use a specific control.
-   * @return The mock instance.
-   */
-  protected final <T> T createMock(Class<T> toMock, IMocksControl control) {
-    assertFalse("Mocks have already been set to replay", mocksReplayed);
-    final T mock;
-    if (control == null) {
-      if (usePowerMock) {
-        mock = PowerMock.createMock(toMock);
-      } else {
-        mock = EasyMock.createMock(toMock);
-      }
-      assertTrue("Adding " + toMock.getName() + " mock failed", mocks.add(mock));
-    } else {
-      mock = control.createMock(toMock);
-    }
-    return mock;
-  }
-
-  /** Set all registered mocks to replay */
-  protected final void replayMocks() {
-    assertFalse("Mocks have already been set to replay", mocksReplayed);
-    if (usePowerMock) {
-      PowerMock.replayAll();
-    } else {
-      EasyMock.replay(mocks.toArray());
-    }
-    for (IMocksControl mockControl : mockControls) {
-      mockControl.replay();
-    }
-    mocksReplayed = true;
-  }
-
-  /**
-   * Verify all registered mocks
-   *
-   * <p>This method is called automatically at the end of a test. Nevertheless, it is safe to also
-   * call it beforehand, if this better meets the verification part of a test.
-   */
-  // As the PowerMock runner does not pass through runTest, we inject mock
-  // verification through @After
-  @After
-  public final void verifyMocks() {
-    if (!mocks.isEmpty() || !mockControls.isEmpty()) {
-      assertTrue(
-          "Created mocks have not been set to replay. Call replayMocks " + "within the test",
-          mocksReplayed);
-      if (usePowerMock) {
-        PowerMock.verifyAll();
-      } else {
-        EasyMock.verify(mocks.toArray());
-      }
-      for (IMocksControl mockControl : mockControls) {
-        mockControl.verify();
-      }
-    }
-  }
-
-  @Override
-  public void setUp() throws Exception {
-    super.setUp();
-
-    usePowerMock = false;
-    RunWith runWith = this.getClass().getAnnotation(RunWith.class);
-    if (runWith != null) {
-      usePowerMock = PowerMockRunner.class.isAssignableFrom(runWith.value());
-    }
-
-    mocks = new ArrayList<>();
-    mockControls = new ArrayList<>();
-    mocksReplayed = false;
-  }
-
-  @Override
-  protected void runTest() throws Throwable {
-    super.runTest();
-    // Plain JUnit runner does not pick up @After, so we add it here
-    // explicitly. Note, that we cannot put this into tearDown, as failure
-    // to verify mocks would bail out and might leave open resources from
-    // subclasses open.
-    verifyMocks();
-  }
-
-  /**
-   * Create a new Capture.
-   *
-   * @return The created Capture.
-   */
-  protected final <T> Capture<T> createCapture() {
-    return new Capture<>();
-  }
-}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/log/CollectionAppender.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/log/CollectionAppender.java
index c122676..8d918b2 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/log/CollectionAppender.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/log/CollectionAppender.java
@@ -17,18 +17,19 @@
 import com.google.common.collect.Lists;
 import java.util.Collection;
 import java.util.LinkedList;
+import java.util.logging.LogRecord;
 import org.apache.log4j.AppenderSkeleton;
 import org.apache.log4j.spi.LoggingEvent;
 
 /** Log4j appender that logs into a list */
 public class CollectionAppender extends AppenderSkeleton {
-  private Collection<LoggingEvent> events;
+  private Collection<LogRecord> events;
 
   public CollectionAppender() {
     events = new LinkedList<>();
   }
 
-  public CollectionAppender(Collection<LoggingEvent> events) {
+  public CollectionAppender(Collection<LogRecord> events) {
     this.events = events;
   }
 
@@ -39,15 +40,20 @@
 
   @Override
   protected void append(LoggingEvent event) {
-    if (!events.add(event)) {
-      throw new RuntimeException("Could not append event " + event);
+    LogRecord logRecord = LogUtil.logRecordFromLog4jLoggingEvent(event);
+    append(logRecord);
+  }
+
+  public void append(LogRecord record) {
+    if (!events.add(record)) {
+      throw new RuntimeException("Could not append event " + record);
     }
   }
 
   @Override
   public void close() {}
 
-  public Collection<LoggingEvent> getLoggedEvents() {
+  public Collection<LogRecord> getLoggedEvents() {
     return Lists.newLinkedList(events);
   }
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/log/LogUtil.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/log/LogUtil.java
index 6cd633d..17830db 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/log/LogUtil.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/testutil/log/LogUtil.java
@@ -14,18 +14,141 @@
 
 package com.googlesource.gerrit.plugins.its.base.testutil.log;
 
+import com.google.common.collect.ImmutableMap;
+import com.google.common.flogger.FluentLogger;
 import java.util.Collection;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
 import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
 import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.ThrowableInformation;
 
+/** Utility functions for dealing with various Loggers */
 public class LogUtil {
+  private static final ImmutableMap<org.apache.log4j.Level, Level> log4jToJul =
+      new ImmutableMap.Builder<org.apache.log4j.Level, Level>()
+          .put(org.apache.log4j.Level.OFF, Level.OFF)
+          .put(org.apache.log4j.Level.FATAL, Level.SEVERE)
+          .put(org.apache.log4j.Level.ERROR, Level.SEVERE)
+          .put(org.apache.log4j.Level.WARN, Level.WARNING)
+          .put(org.apache.log4j.Level.INFO, Level.INFO)
+          .put(org.apache.log4j.Level.DEBUG, Level.FINE)
+          .put(org.apache.log4j.Level.TRACE, Level.FINEST)
+          .put(org.apache.log4j.Level.ALL, Level.FINEST)
+          .build();
+
+  /**
+   * Makes sure that Loggers for a given name add their events to a collection
+   *
+   * <p>This is useful for capturing logged events during testing and being able to run assertions
+   * on them.
+   *
+   * <p>We will never be able to cover all possible backends of the Logging flavour of the day. For
+   * now we cover Log4j and JUL. If you use a different default logging backend, please send in
+   * patches.
+   *
+   * @param logName The name of the loggers to make log to the given collection.
+   * @param collection The collection to add log events to.
+   * @param level The level the logger should be set to.
+   */
   public static CollectionAppender logToCollection(
-      String logName, Collection<LoggingEvent> collection) {
+      String logName, Collection<LogRecord> collection, org.apache.log4j.Level level) {
+
+    CollectionAppender appender = new CollectionAppender(collection);
+
+    logToCollectionLog4j(logName, appender, level);
+    logToCollectionJul(logName, appender, log4jToJul.get(level));
+
+    return appender;
+  }
+
+  /**
+   * Make a Log4j logger log to a given appender at a certain level
+   *
+   * @param logName The logger that should log to the appender.
+   * @param appender The appender to log to.
+   * @param level The level to user for the logger.
+   */
+  private static void logToCollectionLog4j(
+      String logName, CollectionAppender appender, org.apache.log4j.Level level) {
     Logger log = LogManager.getLogger(logName);
-    CollectionAppender listAppender = new CollectionAppender(collection);
+    log.setLevel(level);
     log.removeAllAppenders();
-    log.addAppender(listAppender);
-    return listAppender;
+    log.addAppender(appender);
+  }
+
+  /**
+   * Make a java.util.logging logger log to a given appender at a certain level
+   *
+   * @param logName The logger that should log to the appender.
+   * @param appender The appender to log to.
+   * @param level The level to user for the logger.
+   */
+  private static void logToCollectionJul(String logName, CollectionAppender appender, Level level) {
+    // We'd love to simply get the logger of name `logName` and directly
+    // configure that. While this works for running the tests in bazel, it
+    // fails when running tests from within Eclipse. In Eclipse getting the
+    // logger of the same name here and from the class-under-test will get two
+    // different loggers, due to backend calling from a different class. So we
+    // instead resort to configuring the root logger and filtering the logName
+    // in the appender.
+
+    // The description above works for the 2nd, 3rd, ... test of a test case in
+    // Eclipse, but not for the first. To cover the first test as well, we
+    // beforehand tell Flogger to set things up by getting any random logger
+    // /before/ we configure the root logger.
+    @SuppressWarnings("unused")
+    FluentLogger unused = FluentLogger.forEnclosingClass();
+
+    java.util.logging.Logger julLogger = java.util.logging.Logger.getLogger("");
+    julLogger.setLevel(level);
+
+    julLogger.addHandler(
+        new Handler() {
+          @Override
+          public void publish(LogRecord record) {
+            if (record.getLoggerName().equals(logName)) {
+              appender.append(record);
+            }
+          }
+
+          @Override
+          public void flush() {}
+
+          @Override
+          public void close() throws SecurityException {}
+        });
+  }
+
+  /**
+   * Converts a Log4j Logging Event to a JUL LogRecord
+   *
+   * <p>This is not a full conversion, but covers only the fields we care about. That is the logged
+   * message and eventual thrown Throwables.
+   *
+   * @param event The Log4j LoggingEvent to convert
+   * @return The corresponding JUL LogRecord
+   */
+  public static LogRecord logRecordFromLog4jLoggingEvent(LoggingEvent event) {
+    LogRecord logRecord = new LogRecord(Level.ALL, event.getRenderedMessage());
+    ThrowableInformation tInfo = event.getThrowableInformation();
+    if (tInfo != null) {
+      logRecord.setThrown(tInfo.getThrowable());
+    }
+    return logRecord;
+  }
+
+  /**
+   * Check if a JUL and a Log4j Level correspond
+   *
+   * @param left The JUL Level to check.
+   * @param right The Log4j Level to check.
+   * @return True, if and only if the levels correspond.
+   */
+  public static boolean equalLevels(Level left, org.apache.log4j.Level right) {
+    Level julRight = log4jToJul.get(right);
+    return (left == null && right == null) || (left != null && left.equals(julRight));
   }
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/util/CommitMessageFetcherTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/util/CommitMessageFetcherTest.java
index 890e182..9a7faa2 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/util/CommitMessageFetcherTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/util/CommitMessageFetcherTest.java
@@ -19,7 +19,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.entities.Project;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.googlesource.gerrit.plugins.its.base.testutil.LoggingMockingTestCase;
 import java.io.IOException;
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractorTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractorTest.java
index 80cbfd3..3ea73d0 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractorTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/util/IssueExtractorTest.java
@@ -13,14 +13,16 @@
 // limitations under the License.
 package com.googlesource.gerrit.plugins.its.base.util;
 
-import static org.easymock.EasyMock.expect;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.entities.PatchSet;
 import com.google.gerrit.extensions.config.FactoryModule;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.reviewdb.client.RevId;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.googlesource.gerrit.plugins.its.base.its.ItsConfig;
@@ -31,12 +33,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.regex.Pattern;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({PatchSet.class, RevId.class})
 public class IssueExtractorTest extends LoggingMockingTestCase {
   private Injector injector;
   private ItsConfig itsConfig;
@@ -46,124 +43,127 @@
   public void testIssueIdsNullPattern() {
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
 
-    expect(itsConfig.getIssuePattern()).andReturn(null).atLeastOnce();
-
-    replayMocks();
-
     String[] ret = issueExtractor.getIssueIds("Test");
     assertEquals("Number of found ids do not match", 0, ret.length);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
   }
 
   public void testIssueIdsNoMatch() {
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
 
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
     String[] ret = issueExtractor.getIssueIds("Test");
     assertEquals("Number of found ids do not match", 0, ret.length);
 
     assertLogMessageContains("Matching");
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsEmptyGroup() {
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
 
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(X*)(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(X*)(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
     String[] ret = issueExtractor.getIssueIds("bug#4711");
     assertEquals("Number of found ids do not match", 0, ret.length);
 
     assertLogMessageContains("Matching");
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsFullMatch() {
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
 
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
     String[] ret = issueExtractor.getIssueIds("bug#4711");
     assertEquals("Number of found ids do not match", 1, ret.length);
     assertEquals("First found issue id do not match", "4711", ret[0]);
 
     assertLogMessageContains("Matching");
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsMatch() {
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
 
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
     String[] ret = issueExtractor.getIssueIds("Foo bug#4711 bar");
     assertEquals("Number of found ids do not match", 1, ret.length);
     assertEquals("Found issue id does not match", "4711", ret[0]);
 
     assertLogMessageContains("Matching");
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsGrouplessMatch() {
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
 
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#\\d+")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(0).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#\\d+"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(0);
 
     String[] ret = issueExtractor.getIssueIds("Foo bug#4711 bar");
     assertEquals("Number of found ids do not match", 1, ret.length);
     assertEquals("Found issue id does not match", "bug#4711", ret[0]);
 
     assertLogMessageContains("Matching");
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsMultiGroupMatchGroup1() {
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
 
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d)(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d)(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
     String[] ret = issueExtractor.getIssueIds("Foo bug#4711 bar");
     assertEquals("Number of found ids do not match", 1, ret.length);
     assertEquals("Found issue id does not match", "4", ret[0]);
 
     assertLogMessageContains("Matching");
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsMultiGroupMatchGroup2() {
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
 
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d)(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(2).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d)(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(2);
 
     String[] ret = issueExtractor.getIssueIds("Foo bug#4711 bar");
     assertEquals("Number of found ids do not match", 1, ret.length);
     assertEquals("Found issue id does not match", "711", ret[0]);
 
     assertLogMessageContains("Matching");
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsMulipleMatches() {
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
 
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
     String[] ret = issueExtractor.getIssueIds("Foo bug#4711 bug#42 bar bug#123");
     assertEquals("Number of found ids do not match", 3, ret.length);
@@ -173,15 +173,16 @@
     assertTrue("123 not among the extracted ids", retList.contains("123"));
 
     assertLogMessageContains("Matching");
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsMulipleMatchesWithDuplicates() {
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
 
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
     String[] ret = issueExtractor.getIssueIds("Foo bug#4711 bug#42 bar\n" + "bug#123 baz bug#42");
     assertEquals("Number of found ids do not match", 3, ret.length);
@@ -191,18 +192,18 @@
     assertTrue("123 not among the extracted ids", retList.contains("123"));
 
     assertLogMessageContains("Matching");
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitSingleIssue() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn("bug#42\n" + "\n" + "Change-Id: I1234567891123456789212345678931234567894");
-
-    replayMocks();
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn("bug#42\n" + "\n" + "Change-Id: I1234567891123456789212345678931234567894");
 
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
@@ -212,27 +213,23 @@
     expected.put("42", Sets.newHashSet("somewhere", "subject"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 5);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitMultipleIssues() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "bug#42, and bug#4711\n"
                 + "\n"
                 + "Change-Id: I1234567891123456789212345678931234567894");
 
-    replayMocks();
-
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
         issueExtractor.getIssueIds("testProject", "1234567891123456789212345678931234567894");
@@ -242,27 +239,23 @@
     expected.put("4711", Sets.newHashSet("somewhere", "subject"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 5);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitMultipleIssuesMultipleTimes() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "bug#42, bug#4711, bug#4711, bug#42, and bug#4711\n"
                 + "\n"
                 + "Change-Id: I1234567891123456789212345678931234567894");
 
-    replayMocks();
-
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
         issueExtractor.getIssueIds("testProject", "1234567891123456789212345678931234567894");
@@ -272,29 +265,25 @@
     expected.put("4711", Sets.newHashSet("somewhere", "subject"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 5);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitSingleIssueBody() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "Subject does not reference a bug\n"
                 + "Body references bug#42\n"
                 + "\n"
                 + "Footer: does not reference a bug\n"
                 + "Change-Id: I1234567891123456789212345678931234567894");
 
-    replayMocks();
-
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
         issueExtractor.getIssueIds("testProject", "1234567891123456789212345678931234567894");
@@ -303,30 +292,25 @@
     expected.put("42", Sets.newHashSet("somewhere", "body"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 6);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitSingleIssueFooter() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "Subject does not reference a bug\n"
                 + "Body does not reference a bug\n"
                 + "\n"
                 + "Footer: references bug#42\n"
                 + "Change-Id: I1234567891123456789212345678931234567894");
 
-    replayMocks();
-
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
         issueExtractor.getIssueIds("testProject", "1234567891123456789212345678931234567894");
@@ -335,22 +319,19 @@
     expected.put("42", Sets.newHashSet("somewhere", "footer", "footer-Footer"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 6);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitMultipleIssuesFooter() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "Subject does not reference a bug\n"
                 + "Body does not reference a bug\n"
                 + "\n"
@@ -361,8 +342,6 @@
                 + "Change-Id: I1234567891123456789212345678931234567894\n"
                 + "KeyZ: references bug#256");
 
-    replayMocks();
-
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
         issueExtractor.getIssueIds("testProject", "1234567891123456789212345678931234567894");
@@ -374,25 +353,19 @@
     expected.put("4711", Sets.newHashSet("somewhere", "footer"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 9);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitDifferentParts() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "Subject references bug#42.\n"
                 + "Body references bug#16.\n"
                 + "Body also references bug#176.\n"
@@ -400,8 +373,6 @@
                 + "Bug: bug#4711 in footer\n"
                 + "Change-Id: I1234567891123456789212345678931234567894");
 
-    replayMocks();
-
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
         issueExtractor.getIssueIds("testProject", "1234567891123456789212345678931234567894");
@@ -413,22 +384,19 @@
     expected.put("4711", Sets.newHashSet("somewhere", "footer", "footer-Bug"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 6);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitDifferentPartsEmptySubject() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "\n"
                 + "Body references bug#16.\n"
                 + "Body also references bug#176.\n"
@@ -436,8 +404,6 @@
                 + "Bug: bug#4711 in footer\n"
                 + "Change-Id: I1234567891123456789212345678931234567894");
 
-    replayMocks();
-
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
         issueExtractor.getIssueIds("testProject", "1234567891123456789212345678931234567894");
@@ -448,22 +414,19 @@
     expected.put("4711", Sets.newHashSet("somewhere", "footer", "footer-Bug"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 6);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitDifferentPartsLinePastFooter() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "Subject references bug#42.\n"
                 + "Body references bug#16.\n"
                 + "Body also references bug#176.\n"
@@ -471,8 +434,6 @@
                 + "Bug: bug#4711 in footer\n"
                 + "Change-Id: I1234567891123456789212345678931234567894\n");
 
-    replayMocks();
-
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
         issueExtractor.getIssueIds("testProject", "1234567891123456789212345678931234567894");
@@ -484,22 +445,19 @@
     expected.put("4711", Sets.newHashSet("somewhere", "footer", "footer-Bug"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 6);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitDifferentPartsLinesPastFooter() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "Subject references bug#42.\n"
                 + "Body references bug#16.\n"
                 + "Body also references bug#176.\n"
@@ -508,8 +466,6 @@
                 + "Change-Id: I1234567891123456789212345678931234567894\n"
                 + "\n");
 
-    replayMocks();
-
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
         issueExtractor.getIssueIds("testProject", "1234567891123456789212345678931234567894");
@@ -521,28 +477,23 @@
     expected.put("4711", Sets.newHashSet("somewhere", "footer", "footer-Bug"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 6);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitDifferentPartsNoFooter() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "Subject references bug#42.\n"
                 + "Body references bug#16.\n"
                 + "Body also references bug#176.");
 
-    replayMocks();
-
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
         issueExtractor.getIssueIds("testProject", "1234567891123456789212345678931234567894");
@@ -553,25 +504,23 @@
     expected.put("176", Sets.newHashSet("somewhere", "body"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 3);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitDifferentPartsNoFooterTrailingLine() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "Subject references bug#42.\n"
                 + "Body references bug#16.\n"
                 + "Body also references bug#176.\n");
 
-    replayMocks();
-
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
         issueExtractor.getIssueIds("testProject", "1234567891123456789212345678931234567894");
@@ -582,26 +531,24 @@
     expected.put("176", Sets.newHashSet("somewhere", "body"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 3);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitDifferentPartsNoFooterTrailingLines() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "Subject references bug#42.\n"
                 + "Body references bug#16.\n"
                 + "Body also references bug#176.\n"
                 + "\n");
 
-    replayMocks();
-
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
         issueExtractor.getIssueIds("testProject", "1234567891123456789212345678931234567894");
@@ -612,21 +559,19 @@
     expected.put("176", Sets.newHashSet("somewhere", "body"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 3);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitEmpty() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn("");
-
-    replayMocks();
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn("");
 
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
@@ -635,21 +580,19 @@
     Map<String, Set<String>> expected = Maps.newHashMap();
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 3);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitBlankLine() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn("\n");
-
-    replayMocks();
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn("\n");
 
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
@@ -659,18 +602,18 @@
     assertEquals("Extracted issues do not match", expected, actual);
 
     assertLogMessageContains("Matching");
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitBlankLines() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn("\n\n");
-
-    replayMocks();
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn("\n\n");
 
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
@@ -680,18 +623,18 @@
     assertEquals("Extracted issues do not match", expected, actual);
 
     assertLogMessageContains("Matching");
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitMoreBlankLines() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn("\n\n\n");
-
-    replayMocks();
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn("\n\n\n");
 
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
@@ -701,16 +644,18 @@
     assertEquals("Extracted issues do not match", expected, actual);
 
     assertLogMessageContains("Matching");
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitMixed() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "Subject bug#42, bug#1984, and bug#16\n"
                 + "\n"
                 + "bug#4711 in body,\n"
@@ -720,8 +665,6 @@
                 + "Bug: bug#176, bug#1984, and bug#5150\n"
                 + "Change-Id: I1234567891123456789212345678931234567894");
 
-    replayMocks();
-
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
         issueExtractor.getIssueIds("testProject", "1234567891123456789212345678931234567894");
@@ -735,26 +678,21 @@
     expected.put("5150", Sets.newHashSet("somewhere", "body", "footer", "footer-Bug"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 6);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitWAddedEmptyFirst() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn("");
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn("");
 
-    replayMocks();
-
-    PatchSet.Id patchSetId = new PatchSet.Id(new Change.Id(4), 1);
+    PatchSet.Id patchSetId = PatchSet.id(Change.id(4), 1);
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
         issueExtractor.getIssueIds(
@@ -763,27 +701,25 @@
     Map<String, Set<String>> expected = Maps.newHashMap();
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 3);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitWAddedSingleSubjectIssueFirst() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    Change.Id changeId = createMock(Change.Id.class);
+    Change.Id changeId = mock(Change.Id.class);
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn("bug#42\n" + "\n" + "Change-Id: I1234567891123456789212345678931234567894");
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn("bug#42\n" + "\n" + "Change-Id: I1234567891123456789212345678931234567894");
 
-    PatchSet.Id currentPatchSetId = createMock(PatchSet.Id.class);
-    expect(currentPatchSetId.get()).andReturn(1).anyTimes();
-    expect(currentPatchSetId.getParentKey()).andReturn(changeId).anyTimes();
-
-    replayMocks();
+    PatchSet.Id currentPatchSetId = mock(PatchSet.Id.class);
+    when(currentPatchSetId.get()).thenReturn(1);
+    when(currentPatchSetId.changeId()).thenReturn(changeId);
 
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
@@ -794,40 +730,34 @@
     expected.put("42", Sets.newHashSet("somewhere", "subject", "added@somewhere", "added@subject"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 5);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitWAddedSingleSubjectIssueSecondEmpty() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    Change.Id changeId = createMock(Change.Id.class);
+    Change.Id changeId = mock(Change.Id.class);
 
     // Call for current patch set
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn("bug#42\n" + "\n" + "Change-Id: I1234567891123456789212345678931234567894");
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn("bug#42\n" + "\n" + "Change-Id: I1234567891123456789212345678931234567894");
 
     // Call for previous patch set
-    PatchSet.Id previousPatchSetId = new PatchSet.Id(changeId, 1);
-    expect(db.getRevision(previousPatchSetId))
-        .andReturn("9876543211987654321298765432139876543214");
+    PatchSet.Id previousPatchSetId = PatchSet.id(changeId, 1);
+    when(db.getRevision(previousPatchSetId)).thenReturn("9876543211987654321298765432139876543214");
 
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "9876543211987654321298765432139876543214"))
-        .andReturn("subject\n" + "\n" + "Change-Id: I9876543211987654321298765432139876543214");
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "9876543211987654321298765432139876543214"))
+        .thenReturn("subject\n" + "\n" + "Change-Id: I9876543211987654321298765432139876543214");
 
-    PatchSet.Id currentPatchSetId = createMock(PatchSet.Id.class);
-    expect(currentPatchSetId.get()).andReturn(2).anyTimes();
-    expect(currentPatchSetId.getParentKey()).andReturn(changeId).anyTimes();
-
-    replayMocks();
+    PatchSet.Id currentPatchSetId = mock(PatchSet.Id.class);
+    when(currentPatchSetId.get()).thenReturn(2);
+    when(currentPatchSetId.changeId()).thenReturn(changeId);
 
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
@@ -838,45 +768,34 @@
     expected.put("42", Sets.newHashSet("somewhere", "subject", "added@somewhere", "added@subject"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 10);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitWAddedSingleSubjectIssueSecondSame() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    Change.Id changeId = createMock(Change.Id.class);
+    Change.Id changeId = mock(Change.Id.class);
 
     // Call for current patch set
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn("bug#42\n" + "\n" + "Change-Id: I1234567891123456789212345678931234567894");
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn("bug#42\n" + "\n" + "Change-Id: I1234567891123456789212345678931234567894");
 
     // Call for previous patch set
-    PatchSet.Id previousPatchSetId = new PatchSet.Id(changeId, 1);
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "9876543211987654321298765432139876543214"))
-        .andReturn("bug#42\n" + "\n" + "Change-Id: I9876543211987654321298765432139876543214");
+    PatchSet.Id previousPatchSetId = PatchSet.id(changeId, 1);
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "9876543211987654321298765432139876543214"))
+        .thenReturn("bug#42\n" + "\n" + "Change-Id: I9876543211987654321298765432139876543214");
 
-    expect(db.getRevision(previousPatchSetId))
-        .andReturn("9876543211987654321298765432139876543214");
+    when(db.getRevision(previousPatchSetId)).thenReturn("9876543211987654321298765432139876543214");
 
-    PatchSet.Id currentPatchSetId = createMock(PatchSet.Id.class);
-    expect(currentPatchSetId.get()).andReturn(2).anyTimes();
-    expect(currentPatchSetId.getParentKey()).andReturn(changeId).anyTimes();
-
-    replayMocks();
+    PatchSet.Id currentPatchSetId = mock(PatchSet.Id.class);
+    when(currentPatchSetId.get()).thenReturn(2);
+    when(currentPatchSetId.changeId()).thenReturn(changeId);
 
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
@@ -887,49 +806,38 @@
     expected.put("42", Sets.newHashSet("somewhere", "subject"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 10);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitWAddedSingleSubjectIssueSecondBody() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    Change.Id changeId = createMock(Change.Id.class);
+    Change.Id changeId = mock(Change.Id.class);
 
     // Call for current patch set
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn("bug#42\n" + "\n" + "Change-Id: I1234567891123456789212345678931234567894");
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn("bug#42\n" + "\n" + "Change-Id: I1234567891123456789212345678931234567894");
 
     // Call for previous patch set
-    PatchSet.Id previousPatchSetId = new PatchSet.Id(changeId, 1);
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "9876543211987654321298765432139876543214"))
-        .andReturn(
+    PatchSet.Id previousPatchSetId = PatchSet.id(changeId, 1);
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "9876543211987654321298765432139876543214"))
+        .thenReturn(
             "subject\n"
                 + "bug#42\n"
                 + "\n"
                 + "Change-Id: I9876543211987654321298765432139876543214");
 
-    expect(db.getRevision(previousPatchSetId))
-        .andReturn("9876543211987654321298765432139876543214");
+    when(db.getRevision(previousPatchSetId)).thenReturn("9876543211987654321298765432139876543214");
 
-    PatchSet.Id currentPatchSetId = createMock(PatchSet.Id.class);
-    expect(currentPatchSetId.get()).andReturn(2).anyTimes();
-    expect(currentPatchSetId.getParentKey()).andReturn(changeId).anyTimes();
-
-    replayMocks();
+    PatchSet.Id currentPatchSetId = mock(PatchSet.Id.class);
+    when(currentPatchSetId.get()).thenReturn(2);
+    when(currentPatchSetId.changeId()).thenReturn(changeId);
 
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
@@ -940,49 +848,38 @@
     expected.put("42", Sets.newHashSet("somewhere", "subject", "added@subject"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 10);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitWAddedSingleSubjectIssueSecondFooter() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    Change.Id changeId = createMock(Change.Id.class);
+    Change.Id changeId = mock(Change.Id.class);
 
     // Call for current patch set
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "subject\n"
                 + "\n"
                 + "Bug: bug#42\n"
                 + "Change-Id: I1234567891123456789212345678931234567894");
 
     // Call for previous patch set
-    PatchSet.Id previousPatchSetId = new PatchSet.Id(changeId, 1);
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "9876543211987654321298765432139876543214"))
-        .andReturn("bug#42\n" + "\n" + "Change-Id: I9876543211987654321298765432139876543214");
+    PatchSet.Id previousPatchSetId = PatchSet.id(changeId, 1);
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "9876543211987654321298765432139876543214"))
+        .thenReturn("bug#42\n" + "\n" + "Change-Id: I9876543211987654321298765432139876543214");
 
-    expect(db.getRevision(previousPatchSetId))
-        .andReturn("9876543211987654321298765432139876543214");
+    when(db.getRevision(previousPatchSetId)).thenReturn("9876543211987654321298765432139876543214");
 
-    PatchSet.Id currentPatchSetId = createMock(PatchSet.Id.class);
-    expect(currentPatchSetId.get()).andReturn(2).anyTimes();
-    expect(currentPatchSetId.getParentKey()).andReturn(changeId).anyTimes();
-
-    replayMocks();
+    PatchSet.Id currentPatchSetId = mock(PatchSet.Id.class);
+    when(currentPatchSetId.get()).thenReturn(2);
+    when(currentPatchSetId.changeId()).thenReturn(changeId);
 
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
@@ -995,30 +892,22 @@
         Sets.newHashSet("somewhere", "footer", "added@footer", "footer-Bug", "added@footer-Bug"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 11);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitWAddedSubjectFooter() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    Change.Id changeId = createMock(Change.Id.class);
+    Change.Id changeId = mock(Change.Id.class);
 
     // Call for current patch set
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "subject bug#42\n"
                 + "\n"
                 + "body bug#42\n"
@@ -1027,24 +916,20 @@
                 + "Change-Id: I1234567891123456789212345678931234567894");
 
     // Call for previous patch set
-    PatchSet.Id previousPatchSetId = new PatchSet.Id(changeId, 1);
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "9876543211987654321298765432139876543214"))
-        .andReturn(
+    PatchSet.Id previousPatchSetId = PatchSet.id(changeId, 1);
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "9876543211987654321298765432139876543214"))
+        .thenReturn(
             "subject\n"
                 + "bug#42\n"
                 + "\n"
                 + "Change-Id: I9876543211987654321298765432139876543214");
 
-    expect(db.getRevision(previousPatchSetId))
-        .andReturn("9876543211987654321298765432139876543214");
+    when(db.getRevision(previousPatchSetId)).thenReturn("9876543211987654321298765432139876543214");
 
-    PatchSet.Id currentPatchSetId = createMock(PatchSet.Id.class);
-    expect(currentPatchSetId.get()).andReturn(2).anyTimes();
-    expect(currentPatchSetId.getParentKey()).andReturn(changeId).anyTimes();
-
-    replayMocks();
+    PatchSet.Id currentPatchSetId = mock(PatchSet.Id.class);
+    when(currentPatchSetId.get()).thenReturn(2);
+    when(currentPatchSetId.changeId()).thenReturn(changeId);
 
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
@@ -1065,30 +950,22 @@
             "added@footer-Bug"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 11);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
   }
 
   public void testIssueIdsCommitWAddedMultiple() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).atLeastOnce();
-    expect(itsConfig.getIssuePatternGroupIndex()).andReturn(1).atLeastOnce();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    when(itsConfig.getIssuePatternGroupIndex()).thenReturn(1);
 
-    Change.Id changeId = createMock(Change.Id.class);
+    Change.Id changeId = mock(Change.Id.class);
 
     // Call for current patch set
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "1234567891123456789212345678931234567894"))
-        .andReturn(
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "1234567891123456789212345678931234567894"))
+        .thenReturn(
             "subject bug#42\n"
                 + "\n"
                 + "body bug#42 bug#16\n"
@@ -1097,25 +974,21 @@
                 + "Change-Id: I1234567891123456789212345678931234567894");
 
     // Call for previous patch set
-    PatchSet.Id previousPatchSetId = new PatchSet.Id(changeId, 1);
-    expect(
-            commitMessageFetcher.fetchGuarded(
-                "testProject", "9876543211987654321298765432139876543214"))
-        .andReturn(
+    PatchSet.Id previousPatchSetId = PatchSet.id(changeId, 1);
+    when(commitMessageFetcher.fetchGuarded(
+            "testProject", "9876543211987654321298765432139876543214"))
+        .thenReturn(
             "subject\n"
                 + "bug#42 bug#4711\n"
                 + "\n"
                 + "Bug: bug#16\n"
                 + "Change-Id: I9876543211987654321298765432139876543214");
 
-    expect(db.getRevision(previousPatchSetId))
-        .andReturn("9876543211987654321298765432139876543214");
+    when(db.getRevision(previousPatchSetId)).thenReturn("9876543211987654321298765432139876543214");
 
-    PatchSet.Id currentPatchSetId = createMock(PatchSet.Id.class);
-    expect(currentPatchSetId.get()).andReturn(2).anyTimes();
-    expect(currentPatchSetId.getParentKey()).andReturn(changeId).anyTimes();
-
-    replayMocks();
+    PatchSet.Id currentPatchSetId = mock(PatchSet.Id.class);
+    when(currentPatchSetId.get()).thenReturn(2);
+    when(currentPatchSetId.changeId()).thenReturn(changeId);
 
     IssueExtractor issueExtractor = injector.getInstance(IssueExtractor.class);
     Map<String, Set<String>> actual =
@@ -1137,18 +1010,14 @@
             "added@footer-Bug"));
     assertEquals("Extracted issues do not match", expected, actual);
 
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
-    assertLogMessageContains("Matching");
+    assertLogMessageContains("Matching", 12);
+
+    verifyOneOrMore(itsConfig).getIssuePattern();
+    verifyOneOrMore(itsConfig).getIssuePatternGroupIndex();
+  }
+
+  private <T> T verifyOneOrMore(T mock) {
+    return verify(mock, atLeastOnce());
   }
 
   @Override
@@ -1161,13 +1030,13 @@
   private class TestModule extends FactoryModule {
     @Override
     protected void configure() {
-      itsConfig = createMock(ItsConfig.class);
+      itsConfig = mock(ItsConfig.class);
       bind(ItsConfig.class).toInstance(itsConfig);
 
-      commitMessageFetcher = createMock(CommitMessageFetcher.class);
+      commitMessageFetcher = mock(CommitMessageFetcher.class);
       bind(CommitMessageFetcher.class).toInstance(commitMessageFetcher);
 
-      db = createMock(PatchSetDb.class);
+      db = mock(PatchSetDb.class);
       bind(PatchSetDb.class).toInstance(db);
     }
   }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/util/ItsProjectExtractorTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/util/ItsProjectExtractorTest.java
index 0aecd05..2fbca57 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/util/ItsProjectExtractorTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/util/ItsProjectExtractorTest.java
@@ -14,17 +14,18 @@
 
 package com.googlesource.gerrit.plugins.its.base.util;
 
-import static org.easymock.EasyMock.expect;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
+import com.google.gerrit.entities.Project;
 import com.google.gerrit.extensions.config.FactoryModule;
-import com.google.gerrit.reviewdb.client.Project;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.googlesource.gerrit.plugins.its.base.its.ItsConfig;
-import com.googlesource.gerrit.plugins.its.base.testutil.MockingTestCase;
 import java.util.Optional;
+import junit.framework.TestCase;
 
-public class ItsProjectExtractorTest extends MockingTestCase {
+public class ItsProjectExtractorTest extends TestCase {
 
   private static final String PROJECT = "project";
   private static final String ITS_PROJECT = "itsProject";
@@ -35,11 +36,9 @@
   public void test() {
     ItsProjectExtractor projectExtractor = injector.getInstance(ItsProjectExtractor.class);
 
-    expect(itsConfig.getItsProjectName(new Project.NameKey(PROJECT)))
-        .andReturn(Optional.of(ITS_PROJECT))
-        .once();
-
-    replayMocks();
+    when(itsConfig.getItsProjectName(Project.nameKey(PROJECT)))
+        .thenReturn(Optional.of(ITS_PROJECT))
+        .thenThrow(new UnsupportedOperationException("Method more than once"));
 
     String ret = projectExtractor.getItsProject(PROJECT).orElse(null);
     assertEquals(ret, ITS_PROJECT);
@@ -55,7 +54,7 @@
   private class TestModule extends FactoryModule {
     @Override
     protected void configure() {
-      itsConfig = createMock(ItsConfig.class);
+      itsConfig = mock(ItsConfig.class);
       bind(ItsConfig.class).toInstance(itsConfig);
     }
   }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/util/PropertyAttributeExtractorTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/util/PropertyAttributeExtractorTest.java
index df88c2f..153f1c3 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/util/PropertyAttributeExtractorTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/util/PropertyAttributeExtractorTest.java
@@ -13,13 +13,14 @@
 // limitations under the License.
 package com.googlesource.gerrit.plugins.its.base.util;
 
-import static org.easymock.EasyMock.expect;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.entities.Change.Status;
 import com.google.gerrit.extensions.config.FactoryModule;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.Change.Status;
 import com.google.gerrit.server.data.AccountAttribute;
 import com.google.gerrit.server.data.ApprovalAttribute;
 import com.google.gerrit.server.data.ChangeAttribute;
@@ -38,8 +39,6 @@
   private ItsFacade facade;
 
   public void testAccountAttributeNull() {
-    replayMocks();
-
     PropertyAttributeExtractor extractor = injector.getInstance(PropertyAttributeExtractor.class);
 
     Map<String, String> actual = extractor.extractFrom(null, "prefix");
@@ -55,8 +54,6 @@
     accountAttribute.name = "testName";
     accountAttribute.username = "testUsername";
 
-    replayMocks();
-
     PropertyAttributeExtractor extractor = injector.getInstance(PropertyAttributeExtractor.class);
 
     Map<String, String> actual = extractor.extractFrom(accountAttribute, "prefix");
@@ -87,10 +84,8 @@
     changeAttribute.commitMessage = "Commit Message";
     changeAttribute.status = Change.Status.NEW;
 
-    expect(facade.createLinkForWebui("http://www.example.org/test", "http://www.example.org/test"))
-        .andReturn("http://www.example.org/test");
-
-    replayMocks();
+    when(facade.createLinkForWebui("http://www.example.org/test", "http://www.example.org/test"))
+        .thenReturn("http://www.example.org/test");
 
     PropertyAttributeExtractor extractor = injector.getInstance(PropertyAttributeExtractor.class);
 
@@ -133,10 +128,8 @@
     changeAttribute.commitMessage = "Commit Message";
     changeAttribute.status = Change.Status.NEW;
 
-    expect(facade.createLinkForWebui("http://www.example.org/test", "http://www.example.org/test"))
-        .andReturn("http://www.example.org/test");
-
-    replayMocks();
+    when(facade.createLinkForWebui("http://www.example.org/test", "http://www.example.org/test"))
+        .thenReturn("http://www.example.org/test");
 
     PropertyAttributeExtractor extractor = injector.getInstance(PropertyAttributeExtractor.class);
 
@@ -179,10 +172,8 @@
     changeAttribute.owner = owner;
     changeAttribute.commitMessage = "Commit Message";
 
-    expect(facade.createLinkForWebui("http://www.example.org/test", "http://www.example.org/test"))
-        .andReturn("http://www.example.org/test");
-
-    replayMocks();
+    when(facade.createLinkForWebui("http://www.example.org/test", "http://www.example.org/test"))
+        .thenReturn("http://www.example.org/test");
 
     PropertyAttributeExtractor extractor = injector.getInstance(PropertyAttributeExtractor.class);
 
@@ -231,8 +222,6 @@
     patchSetAttribute.uploader = uploader;
     patchSetAttribute.author = author;
 
-    replayMocks();
-
     PropertyAttributeExtractor extractor = injector.getInstance(PropertyAttributeExtractor.class);
 
     Map<String, String> actual = extractor.extractFrom(patchSetAttribute);
@@ -262,8 +251,6 @@
     refUpdateAttribute.oldRev = "9876543211987654321298765432139876543214";
     refUpdateAttribute.refName = "refs/heads/master";
 
-    replayMocks();
-
     PropertyAttributeExtractor extractor = injector.getInstance(PropertyAttributeExtractor.class);
 
     Map<String, String> actual = extractor.extractFrom(refUpdateAttribute);
@@ -284,8 +271,6 @@
     approvalAttribute.type = "TestType";
     approvalAttribute.value = "TestValue";
 
-    replayMocks();
-
     PropertyAttributeExtractor extractor = injector.getInstance(PropertyAttributeExtractor.class);
 
     Map<String, String> actual = extractor.extractFrom(approvalAttribute);
@@ -299,8 +284,6 @@
     approvalAttribute.type = "Test-Type";
     approvalAttribute.value = "TestValue";
 
-    replayMocks();
-
     PropertyAttributeExtractor extractor = injector.getInstance(PropertyAttributeExtractor.class);
 
     Map<String, String> actual = extractor.extractFrom(approvalAttribute);
@@ -318,7 +301,7 @@
   private class TestModule extends FactoryModule {
     @Override
     protected void configure() {
-      facade = createMock(ItsFacade.class);
+      facade = mock(ItsFacade.class);
       bind(ItsFacade.class).toInstance(facade);
     }
   }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractorTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractorTest.java
index bfaa949..bdc697b 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractorTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/util/PropertyExtractorTest.java
@@ -13,18 +13,19 @@
 // limitations under the License.
 package com.googlesource.gerrit.plugins.its.base.util;
 
-import static org.easymock.EasyMock.expect;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import com.google.gerrit.entities.Change;
+import com.google.gerrit.entities.PatchSet;
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.entities.Project.NameKey;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.config.FactoryModule;
-import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.client.Project.NameKey;
 import com.google.gerrit.server.data.AccountAttribute;
 import com.google.gerrit.server.data.ApprovalAttribute;
 import com.google.gerrit.server.data.ChangeAttribute;
@@ -56,9 +57,7 @@
   public void testDummyChangeEvent() {
     PropertyExtractor propertyExtractor = injector.getInstance(PropertyExtractor.class);
 
-    expect(itsProjectExtractor.getItsProject("testProject")).andReturn(Optional.empty());
-
-    replayMocks();
+    when(itsProjectExtractor.getItsProject("testProject")).thenReturn(Optional.empty());
 
     Set<Map<String, String>> actual =
         propertyExtractor.extractFrom(new DummyEvent()).getIssuesProperties();
@@ -70,25 +69,25 @@
   public void testChangeAbandonedEvent() {
     ChangeAbandonedEvent event = new ChangeAbandonedEvent(testChange("testProject", "testBranch"));
 
-    expect(itsProjectExtractor.getItsProject("testProject")).andReturn(Optional.empty());
+    when(itsProjectExtractor.getItsProject("testProject")).thenReturn(Optional.empty());
 
-    ChangeAttribute changeAttribute = createMock(ChangeAttribute.class);
+    ChangeAttribute changeAttribute = mock(ChangeAttribute.class);
     event.change = Suppliers.ofInstance(changeAttribute);
     Map<String, String> changeProperties =
         ImmutableMap.of("project", "testProject", "changeNumber", "176");
-    expect(propertyAttributeExtractor.extractFrom(changeAttribute)).andReturn(changeProperties);
+    when(propertyAttributeExtractor.extractFrom(changeAttribute)).thenReturn(changeProperties);
 
-    AccountAttribute accountAttribute = createMock(AccountAttribute.class);
+    AccountAttribute accountAttribute = mock(AccountAttribute.class);
     event.abandoner = Suppliers.ofInstance(accountAttribute);
     Map<String, String> accountProperties = ImmutableMap.of("abandonerName", "testName");
-    expect(propertyAttributeExtractor.extractFrom(accountAttribute, "abandoner"))
-        .andReturn(accountProperties);
+    when(propertyAttributeExtractor.extractFrom(accountAttribute, "abandoner"))
+        .thenReturn(accountProperties);
 
-    PatchSetAttribute patchSetAttribute = createMock(PatchSetAttribute.class);
+    PatchSetAttribute patchSetAttribute = mock(PatchSetAttribute.class);
     event.patchSet = Suppliers.ofInstance(patchSetAttribute);
     Map<String, String> patchSetProperties =
         ImmutableMap.of("revision", "testRevision", "patchSetNumber", "3");
-    expect(propertyAttributeExtractor.extractFrom(patchSetAttribute)).andReturn(patchSetProperties);
+    when(propertyAttributeExtractor.extractFrom(patchSetAttribute)).thenReturn(patchSetProperties);
 
     event.reason = "testReason";
     changeAttribute.project = "testProject";
@@ -111,25 +110,25 @@
   public void testChangeMergedEvent() {
     ChangeMergedEvent event = new ChangeMergedEvent(testChange("testProject", "testBranch"));
 
-    expect(itsProjectExtractor.getItsProject("testProject")).andReturn(Optional.empty());
+    when(itsProjectExtractor.getItsProject("testProject")).thenReturn(Optional.empty());
 
-    ChangeAttribute changeAttribute = createMock(ChangeAttribute.class);
+    ChangeAttribute changeAttribute = mock(ChangeAttribute.class);
     event.change = Suppliers.ofInstance(changeAttribute);
     Map<String, String> changeProperties =
         ImmutableMap.of("project", "testProject", "changeNumber", "176");
-    expect(propertyAttributeExtractor.extractFrom(changeAttribute)).andReturn(changeProperties);
+    when(propertyAttributeExtractor.extractFrom(changeAttribute)).thenReturn(changeProperties);
 
-    AccountAttribute accountAttribute = createMock(AccountAttribute.class);
+    AccountAttribute accountAttribute = mock(AccountAttribute.class);
     event.submitter = Suppliers.ofInstance(accountAttribute);
     Map<String, String> accountProperties = ImmutableMap.of("submitterName", "testName");
-    expect(propertyAttributeExtractor.extractFrom(accountAttribute, "submitter"))
-        .andReturn(accountProperties);
+    when(propertyAttributeExtractor.extractFrom(accountAttribute, "submitter"))
+        .thenReturn(accountProperties);
 
-    PatchSetAttribute patchSetAttribute = createMock(PatchSetAttribute.class);
+    PatchSetAttribute patchSetAttribute = mock(PatchSetAttribute.class);
     event.patchSet = Suppliers.ofInstance(patchSetAttribute);
     Map<String, String> patchSetProperties =
         ImmutableMap.of("revision", "testRevision", "patchSetNumber", "3");
-    expect(propertyAttributeExtractor.extractFrom(patchSetAttribute)).andReturn(patchSetProperties);
+    when(propertyAttributeExtractor.extractFrom(patchSetAttribute)).thenReturn(patchSetProperties);
 
     changeAttribute.project = "testProject";
     changeAttribute.number = 176;
@@ -150,25 +149,25 @@
   public void testChangeRestoredEvent() {
     ChangeRestoredEvent event = new ChangeRestoredEvent(testChange("testProject", "testBranch"));
 
-    expect(itsProjectExtractor.getItsProject("testProject")).andReturn(Optional.empty());
+    when(itsProjectExtractor.getItsProject("testProject")).thenReturn(Optional.empty());
 
-    ChangeAttribute changeAttribute = createMock(ChangeAttribute.class);
+    ChangeAttribute changeAttribute = mock(ChangeAttribute.class);
     event.change = Suppliers.ofInstance(changeAttribute);
     Map<String, String> changeProperties =
         ImmutableMap.of("project", "testProject", "changeNumber", "176");
-    expect(propertyAttributeExtractor.extractFrom(changeAttribute)).andReturn(changeProperties);
+    when(propertyAttributeExtractor.extractFrom(changeAttribute)).thenReturn(changeProperties);
 
-    AccountAttribute accountAttribute = createMock(AccountAttribute.class);
+    AccountAttribute accountAttribute = mock(AccountAttribute.class);
     event.restorer = Suppliers.ofInstance(accountAttribute);
     Map<String, String> accountProperties = ImmutableMap.of("restorerName", "testName");
-    expect(propertyAttributeExtractor.extractFrom(accountAttribute, "restorer"))
-        .andReturn(accountProperties);
+    when(propertyAttributeExtractor.extractFrom(accountAttribute, "restorer"))
+        .thenReturn(accountProperties);
 
-    PatchSetAttribute patchSetAttribute = createMock(PatchSetAttribute.class);
+    PatchSetAttribute patchSetAttribute = mock(PatchSetAttribute.class);
     event.patchSet = Suppliers.ofInstance(patchSetAttribute);
     Map<String, String> patchSetProperties =
         ImmutableMap.of("revision", "testRevision", "patchSetNumber", "3");
-    expect(propertyAttributeExtractor.extractFrom(patchSetAttribute)).andReturn(patchSetProperties);
+    when(propertyAttributeExtractor.extractFrom(patchSetAttribute)).thenReturn(patchSetProperties);
 
     event.reason = "testReason";
     changeAttribute.project = "testProject";
@@ -191,25 +190,25 @@
   public void testCommentAddedEventWOApprovals() {
     CommentAddedEvent event = new CommentAddedEvent(testChange("testProject", "testBranch"));
 
-    expect(itsProjectExtractor.getItsProject("testProject")).andReturn(Optional.empty());
+    when(itsProjectExtractor.getItsProject("testProject")).thenReturn(Optional.empty());
 
-    ChangeAttribute changeAttribute = createMock(ChangeAttribute.class);
+    ChangeAttribute changeAttribute = mock(ChangeAttribute.class);
     event.change = Suppliers.ofInstance(changeAttribute);
     Map<String, String> changeProperties =
         ImmutableMap.of("project", "testProject", "changeNumber", "176");
-    expect(propertyAttributeExtractor.extractFrom(changeAttribute)).andReturn(changeProperties);
+    when(propertyAttributeExtractor.extractFrom(changeAttribute)).thenReturn(changeProperties);
 
-    AccountAttribute accountAttribute = createMock(AccountAttribute.class);
+    AccountAttribute accountAttribute = mock(AccountAttribute.class);
     event.author = Suppliers.ofInstance(accountAttribute);
     Map<String, String> accountProperties = ImmutableMap.of("commenterName", "testName");
-    expect(propertyAttributeExtractor.extractFrom(accountAttribute, "commenter"))
-        .andReturn(accountProperties);
+    when(propertyAttributeExtractor.extractFrom(accountAttribute, "commenter"))
+        .thenReturn(accountProperties);
 
-    PatchSetAttribute patchSetAttribute = createMock(PatchSetAttribute.class);
+    PatchSetAttribute patchSetAttribute = mock(PatchSetAttribute.class);
     event.patchSet = Suppliers.ofInstance(patchSetAttribute);
     Map<String, String> patchSetProperties =
         ImmutableMap.of("revision", "testRevision", "patchSetNumber", "3");
-    expect(propertyAttributeExtractor.extractFrom(patchSetAttribute)).andReturn(patchSetProperties);
+    when(propertyAttributeExtractor.extractFrom(patchSetAttribute)).thenReturn(patchSetProperties);
 
     event.approvals = Suppliers.ofInstance(null);
 
@@ -234,34 +233,34 @@
   public void testCommentAddedEventWApprovals() {
     CommentAddedEvent event = new CommentAddedEvent(testChange("testProject", "testBranch"));
 
-    expect(itsProjectExtractor.getItsProject("testProject")).andReturn(Optional.empty());
+    when(itsProjectExtractor.getItsProject("testProject")).thenReturn(Optional.empty());
 
-    ChangeAttribute changeAttribute = createMock(ChangeAttribute.class);
+    ChangeAttribute changeAttribute = mock(ChangeAttribute.class);
     event.change = Suppliers.ofInstance(changeAttribute);
     Map<String, String> changeProperties =
         ImmutableMap.of("project", "testProject", "changeNumber", "176");
-    expect(propertyAttributeExtractor.extractFrom(changeAttribute)).andReturn(changeProperties);
+    when(propertyAttributeExtractor.extractFrom(changeAttribute)).thenReturn(changeProperties);
 
-    AccountAttribute accountAttribute = createMock(AccountAttribute.class);
+    AccountAttribute accountAttribute = mock(AccountAttribute.class);
     event.author = Suppliers.ofInstance(accountAttribute);
     Map<String, String> accountProperties = ImmutableMap.of("commenterName", "testName");
-    expect(propertyAttributeExtractor.extractFrom(accountAttribute, "commenter"))
-        .andReturn(accountProperties);
+    when(propertyAttributeExtractor.extractFrom(accountAttribute, "commenter"))
+        .thenReturn(accountProperties);
 
-    PatchSetAttribute patchSetAttribute = createMock(PatchSetAttribute.class);
+    PatchSetAttribute patchSetAttribute = mock(PatchSetAttribute.class);
     event.patchSet = Suppliers.ofInstance(patchSetAttribute);
     Map<String, String> patchSetProperties =
         ImmutableMap.of("revision", "testRevision", "patchSetNumber", "3");
-    expect(propertyAttributeExtractor.extractFrom(patchSetAttribute)).andReturn(patchSetProperties);
+    when(propertyAttributeExtractor.extractFrom(patchSetAttribute)).thenReturn(patchSetProperties);
 
-    ApprovalAttribute approvalAttribute1 = createMock(ApprovalAttribute.class);
+    ApprovalAttribute approvalAttribute1 = mock(ApprovalAttribute.class);
     Map<String, String> approuvalProperties1 = ImmutableMap.of("approvalCodeReview", "0");
-    expect(propertyAttributeExtractor.extractFrom(approvalAttribute1))
-        .andReturn(approuvalProperties1);
-    ApprovalAttribute approvalAttribute2 = createMock(ApprovalAttribute.class);
+    when(propertyAttributeExtractor.extractFrom(approvalAttribute1))
+        .thenReturn(approuvalProperties1);
+    ApprovalAttribute approvalAttribute2 = mock(ApprovalAttribute.class);
     Map<String, String> approuvalProperties2 = ImmutableMap.of("approvalVerified", "0");
-    expect(propertyAttributeExtractor.extractFrom(approvalAttribute2))
-        .andReturn(approuvalProperties2);
+    when(propertyAttributeExtractor.extractFrom(approvalAttribute2))
+        .thenReturn(approuvalProperties2);
     ApprovalAttribute[] approvalAttributes = {approvalAttribute1, approvalAttribute2};
     event.approvals = Suppliers.ofInstance(approvalAttributes);
 
@@ -288,25 +287,25 @@
   public void testPatchSetCreatedEvent() {
     PatchSetCreatedEvent event = new PatchSetCreatedEvent(testChange("testProject", "testBranch"));
 
-    expect(itsProjectExtractor.getItsProject("testProject")).andReturn(Optional.empty());
+    when(itsProjectExtractor.getItsProject("testProject")).thenReturn(Optional.empty());
 
-    ChangeAttribute changeAttribute = createMock(ChangeAttribute.class);
+    ChangeAttribute changeAttribute = mock(ChangeAttribute.class);
     event.change = Suppliers.ofInstance(changeAttribute);
     Map<String, String> changeProperties =
         ImmutableMap.of("project", "testProject", "changeNumber", "176");
-    expect(propertyAttributeExtractor.extractFrom(changeAttribute)).andReturn(changeProperties);
+    when(propertyAttributeExtractor.extractFrom(changeAttribute)).thenReturn(changeProperties);
 
-    AccountAttribute accountAttribute = createMock(AccountAttribute.class);
+    AccountAttribute accountAttribute = mock(AccountAttribute.class);
     event.uploader = Suppliers.ofInstance(accountAttribute);
     Map<String, String> accountProperties = ImmutableMap.of("uploaderName", "testName");
-    expect(propertyAttributeExtractor.extractFrom(accountAttribute, "uploader"))
-        .andReturn(accountProperties);
+    when(propertyAttributeExtractor.extractFrom(accountAttribute, "uploader"))
+        .thenReturn(accountProperties);
 
-    PatchSetAttribute patchSetAttribute = createMock(PatchSetAttribute.class);
+    PatchSetAttribute patchSetAttribute = mock(PatchSetAttribute.class);
     event.patchSet = Suppliers.ofInstance(patchSetAttribute);
     Map<String, String> patchSetProperties =
         ImmutableMap.of("revision", "testRevision", "patchSetNumber", "3");
-    expect(propertyAttributeExtractor.extractFrom(patchSetAttribute)).andReturn(patchSetProperties);
+    when(propertyAttributeExtractor.extractFrom(patchSetAttribute)).thenReturn(patchSetProperties);
 
     changeAttribute.project = "testProject";
     changeAttribute.number = 176;
@@ -327,25 +326,25 @@
   public void testRefUpdatedEvent() {
     RefUpdatedEvent event = new RefUpdatedEvent();
 
-    AccountAttribute accountAttribute = createMock(AccountAttribute.class);
+    AccountAttribute accountAttribute = mock(AccountAttribute.class);
     event.submitter = Suppliers.ofInstance(accountAttribute);
     Map<String, String> accountProperties = ImmutableMap.of("submitterName", "testName");
-    expect(propertyAttributeExtractor.extractFrom(accountAttribute, "submitter"))
-        .andReturn(accountProperties);
+    when(propertyAttributeExtractor.extractFrom(accountAttribute, "submitter"))
+        .thenReturn(accountProperties);
 
-    RefUpdateAttribute refUpdateAttribute = createMock(RefUpdateAttribute.class);
+    RefUpdateAttribute refUpdateAttribute = mock(RefUpdateAttribute.class);
     event.refUpdate = Suppliers.ofInstance(refUpdateAttribute);
     Map<String, String> refUpdatedProperties =
         ImmutableMap.of("revision", "testRevision", "revisionOld", "oldRevision");
-    expect(propertyAttributeExtractor.extractFrom(refUpdateAttribute))
-        .andReturn(refUpdatedProperties);
+    when(propertyAttributeExtractor.extractFrom(refUpdateAttribute))
+        .thenReturn(refUpdatedProperties);
 
     refUpdateAttribute.project = "testProject";
     refUpdateAttribute.newRev = "testRevision";
     refUpdateAttribute.oldRev = "oldRevision";
     refUpdateAttribute.refName = "testBranch";
 
-    expect(itsProjectExtractor.getItsProject("testProject")).andReturn(Optional.empty());
+    when(itsProjectExtractor.getItsProject("testProject")).thenReturn(Optional.empty());
 
     Map<String, String> common =
         ImmutableMap.<String, String>builder()
@@ -370,15 +369,13 @@
     issueMap.put("4711", Sets.newHashSet("body", "anywhere"));
     issueMap.put("42", Sets.newHashSet("footer", "anywhere"));
     if (withRevision) {
-      PatchSet.Id patchSetId = new PatchSet.Id(new Change.Id(176), 3);
-      expect(issueExtractor.getIssueIds("testProject", "testRevision", patchSetId))
-          .andReturn(issueMap);
+      PatchSet.Id patchSetId = PatchSet.id(Change.id(176), 3);
+      when(issueExtractor.getIssueIds("testProject", "testRevision", patchSetId))
+          .thenReturn(issueMap);
     } else {
-      expect(issueExtractor.getIssueIds("testProject", "testRevision")).andReturn(issueMap);
+      when(issueExtractor.getIssueIds("testProject", "testRevision")).thenReturn(issueMap);
     }
 
-    replayMocks();
-
     Set<Map<String, String>> actual = propertyExtractor.extractFrom(event).getIssuesProperties();
 
     Map<String, String> propertiesIssue4711 =
@@ -417,13 +414,13 @@
     protected void configure() {
       bind(String.class).annotatedWith(PluginName.class).toInstance("ItsTestName");
 
-      itsProjectExtractor = createMock(ItsProjectExtractor.class);
+      itsProjectExtractor = mock(ItsProjectExtractor.class);
       bind(ItsProjectExtractor.class).toInstance(itsProjectExtractor);
 
-      issueExtractor = createMock(IssueExtractor.class);
+      issueExtractor = mock(IssueExtractor.class);
       bind(IssueExtractor.class).toInstance(issueExtractor);
 
-      propertyAttributeExtractor = createMock(PropertyAttributeExtractor.class);
+      propertyAttributeExtractor = mock(PropertyAttributeExtractor.class);
       bind(PropertyAttributeExtractor.class).toInstance(propertyAttributeExtractor);
     }
   }
@@ -440,7 +437,7 @@
 
     @Override
     public NameKey getProjectNameKey() {
-      return new Project.NameKey("testProject");
+      return Project.nameKey("testProject");
     }
   }
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/validation/ItsValidateCommentTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/validation/ItsValidateCommentTest.java
index 666d463..433c43e 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/validation/ItsValidateCommentTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/validation/ItsValidateCommentTest.java
@@ -13,11 +13,17 @@
 // limitations under the License.
 package com.googlesource.gerrit.plugins.its.base.validation;
 
-import static org.easymock.EasyMock.expect;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
+import com.google.gerrit.entities.Project;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.config.FactoryModule;
-import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.events.CommitReceivedEvent;
 import com.google.gerrit.server.git.validators.CommitValidationException;
@@ -30,17 +36,14 @@
 import com.googlesource.gerrit.plugins.its.base.testutil.LoggingMockingTestCase;
 import com.googlesource.gerrit.plugins.its.base.util.IssueExtractor;
 import java.io.IOException;
+import java.util.Date;
 import java.util.List;
 import java.util.Optional;
+import java.util.Random;
 import java.util.regex.Pattern;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.transport.ReceiveCommand;
-import org.junit.runner.RunWith;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
 
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({RevCommit.class})
 public class ItsValidateCommentTest extends LoggingMockingTestCase {
   private Injector injector;
   private IssueExtractor issueExtractor;
@@ -48,43 +51,34 @@
   private ItsConfig itsConfig;
   private ItsFacadeFactory itsFacadeFactory;
 
-  private Project project = new Project(new Project.NameKey("myProject"));
+  private Project project = new Project(Project.nameKey("myProject"));
 
   public void testOptional() throws CommitValidationException {
     List<CommitValidationMessage> ret;
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit();
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.OPTIONAL)
-        .atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.OPTIONAL);
 
     ret = ivc.onCommitReceived(event);
 
     assertEmptyList(ret);
+
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
   }
 
   public void testSuggestedNonMatching() throws CommitValidationException {
     List<CommitValidationMessage> ret;
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("TestMessage");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.SUGGESTED)
-        .atLeastOnce();
-    expect(itsConfig.getDummyIssuePattern()).andReturn(Optional.empty()).atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("TestMessage").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("TestMessage")).andReturn(new String[] {}).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.SUGGESTED);
+    when(itsConfig.getDummyIssuePattern()).thenReturn(Optional.empty());
+    when(issueExtractor.getIssueIds("TestMessage")).thenReturn(new String[] {});
 
     ret = ivc.onCommitReceived(event);
 
@@ -92,126 +86,104 @@
     assertTrue(
         "First CommitValidationMessages does not contain 'Missing " + "issue'",
         ret.get(0).getMessage().contains("Missing issue"));
+
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(itsConfig).getDummyIssuePattern();
+    verifyOneOrMore(issueExtractor).getIssueIds("TestMessage");
   }
 
   public void testMandatoryNonMatching() {
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("TestMessage");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.MANDATORY)
-        .atLeastOnce();
-    expect(itsConfig.getDummyIssuePattern()).andReturn(Optional.empty()).atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("TestMessage").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("TestMessage")).andReturn(new String[] {}).atLeastOnce();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.MANDATORY);
+    when(itsConfig.getDummyIssuePattern()).thenReturn(Optional.empty());
+    when(issueExtractor.getIssueIds("TestMessage")).thenReturn(new String[] {});
 
-    replayMocks();
+    CommitValidationException thrown =
+        assertThrows(CommitValidationException.class, () -> ivc.onCommitReceived(event));
+    assertThat(thrown).hasMessageThat().contains("Missing issue");
 
-    try {
-      ivc.onCommitReceived(event);
-      fail("onCommitReceived did not throw any exception");
-    } catch (CommitValidationException e) {
-      assertTrue(
-          "Message of thrown CommitValidationException does not " + "contain 'Missing issue'",
-          e.getMessage().contains("Missing issue"));
-    }
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(itsConfig).getDummyIssuePattern();
+    verifyOneOrMore(issueExtractor).getIssueIds("TestMessage");
   }
 
   public void testOnlySkipMatching() throws CommitValidationException {
     List<CommitValidationMessage> ret;
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("TestMessage SKIP");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.MANDATORY)
-        .atLeastOnce();
-    expect(itsConfig.getDummyIssuePattern())
-        .andReturn(Optional.of(Pattern.compile("SKIP")))
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("TestMessage SKIP").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("TestMessage SKIP")).andReturn(new String[] {}).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.MANDATORY);
+    when(itsConfig.getDummyIssuePattern()).thenReturn(Optional.of(Pattern.compile("SKIP")));
+    when(issueExtractor.getIssueIds("TestMessage SKIP")).thenReturn(new String[] {});
 
     ret = ivc.onCommitReceived(event);
 
     assertEmptyList(ret);
+
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(itsConfig).getDummyIssuePattern();
+    verifyOneOrMore(issueExtractor).getIssueIds("TestMessage SKIP");
   }
 
   public void testSuggestedMatchingSingleExisting() throws CommitValidationException, IOException {
     List<CommitValidationMessage> ret;
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("bug#4711");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.SUGGESTED)
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("bug#4711").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("bug#4711")).andReturn(new String[] {"4711"}).atLeastOnce();
-    expect(itsFacadeFactory.getFacade(project.getNameKey())).andReturn(itsFacade);
-    expect(itsFacade.exists("4711")).andReturn(true).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.SUGGESTED);
+    when(issueExtractor.getIssueIds("bug#4711")).thenReturn(new String[] {"4711"});
+    when(itsFacadeFactory.getFacade(project.getNameKey())).thenReturn(itsFacade);
+    when(itsFacade.exists("4711")).thenReturn(true);
 
     ret = ivc.onCommitReceived(event);
 
     assertEmptyList(ret);
+
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(issueExtractor).getIssueIds("bug#4711");
+    verifyOneOrMore(itsFacade).exists("4711");
   }
 
   public void testMandatoryMatchingSingleExisting() throws CommitValidationException, IOException {
     List<CommitValidationMessage> ret;
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("bug#4711");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.MANDATORY)
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("bug#4711").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("bug#4711")).andReturn(new String[] {"4711"}).atLeastOnce();
-    expect(itsFacadeFactory.getFacade(project.getNameKey())).andReturn(itsFacade);
-    expect(itsFacade.exists("4711")).andReturn(true).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.MANDATORY);
+    when(issueExtractor.getIssueIds("bug#4711")).thenReturn(new String[] {"4711"});
+    when(itsFacadeFactory.getFacade(project.getNameKey())).thenReturn(itsFacade);
+    when(itsFacade.exists("4711")).thenReturn(true);
 
     ret = ivc.onCommitReceived(event);
 
     assertEmptyList(ret);
+
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(issueExtractor).getIssueIds("bug#4711");
+    verifyOneOrMore(itsFacade).exists("4711");
   }
 
   public void testSuggestedMatchingSingleNonExisting()
       throws CommitValidationException, IOException {
     List<CommitValidationMessage> ret;
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("bug#4711");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.SUGGESTED)
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("bug#4711").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("bug#4711")).andReturn(new String[] {"4711"}).atLeastOnce();
-    expect(itsFacadeFactory.getFacade(project.getNameKey())).andReturn(itsFacade);
-    expect(itsFacade.exists("4711")).andReturn(false).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.SUGGESTED);
+    when(issueExtractor.getIssueIds("bug#4711")).thenReturn(new String[] {"4711"});
+    when(itsFacadeFactory.getFacade(project.getNameKey())).thenReturn(itsFacade);
+    when(itsFacade.exists("4711")).thenReturn(false);
 
     ret = ivc.onCommitReceived(event);
 
@@ -222,111 +194,90 @@
     assertTrue(
         "First CommitValidationMessages does not contain '4711'",
         ret.get(0).getMessage().contains("4711"));
+
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(issueExtractor).getIssueIds("bug#4711");
+    verifyOneOrMore(itsFacade).exists("4711");
   }
 
   public void testMandatoryMatchingSingleNonExisting() throws IOException {
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("bug#4711");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.MANDATORY)
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("bug#4711").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("bug#4711")).andReturn(new String[] {"4711"}).atLeastOnce();
-    expect(itsFacadeFactory.getFacade(project.getNameKey())).andReturn(itsFacade);
-    expect(itsFacade.exists("4711")).andReturn(false).atLeastOnce();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.MANDATORY);
+    when(issueExtractor.getIssueIds("bug#4711")).thenReturn(new String[] {"4711"});
+    when(itsFacadeFactory.getFacade(project.getNameKey())).thenReturn(itsFacade);
+    when(itsFacade.exists("4711")).thenReturn(false);
 
-    replayMocks();
+    CommitValidationException thrown =
+        assertThrows(CommitValidationException.class, () -> ivc.onCommitReceived(event));
+    assertThat(thrown).hasMessageThat().contains("Non-existing");
 
-    try {
-      ivc.onCommitReceived(event);
-      fail("onCommitReceived did not throw any exception");
-    } catch (CommitValidationException e) {
-      assertTrue(
-          "Message of thrown CommitValidationException does not " + "contain 'Non-existing'",
-          e.getMessage().contains("Non-existing"));
-    }
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(issueExtractor).getIssueIds("bug#4711");
+    verifyOneOrMore(itsFacade).exists("4711");
   }
 
   public void testSuggestedMatchingMultiple() throws CommitValidationException, IOException {
     List<CommitValidationMessage> ret;
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("bug#4711, bug#42");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.SUGGESTED)
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("bug#4711, bug#42").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("bug#4711, bug#42"))
-        .andReturn(new String[] {"4711", "42"})
-        .atLeastOnce();
-    expect(itsFacadeFactory.getFacade(project.getNameKey())).andReturn(itsFacade).anyTimes();
-    expect(itsFacade.exists("4711")).andReturn(true).atLeastOnce();
-    expect(itsFacade.exists("42")).andReturn(true).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.SUGGESTED);
+    when(issueExtractor.getIssueIds("bug#4711, bug#42")).thenReturn(new String[] {"4711", "42"});
+    when(itsFacadeFactory.getFacade(project.getNameKey())).thenReturn(itsFacade);
+    when(itsFacade.exists("4711")).thenReturn(true);
+    when(itsFacade.exists("42")).thenReturn(true);
 
     ret = ivc.onCommitReceived(event);
 
     assertEmptyList(ret);
+
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(itsFacade).exists("4711");
+    verifyOneOrMore(itsFacade).exists("42");
   }
 
   public void testMandatoryMatchingMultiple() throws CommitValidationException, IOException {
     List<CommitValidationMessage> ret;
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("bug#4711, bug#42");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.MANDATORY)
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("bug#4711, bug#42").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("bug#4711, bug#42"))
-        .andReturn(new String[] {"4711", "42"})
-        .atLeastOnce();
-    expect(itsFacadeFactory.getFacade(project.getNameKey())).andReturn(itsFacade).anyTimes();
-    expect(itsFacade.exists("4711")).andReturn(true).atLeastOnce();
-    expect(itsFacade.exists("42")).andReturn(true).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.MANDATORY);
+    when(issueExtractor.getIssueIds("bug#4711, bug#42")).thenReturn(new String[] {"4711", "42"});
+    when(itsFacadeFactory.getFacade(project.getNameKey())).thenReturn(itsFacade);
+    when(itsFacade.exists("4711")).thenReturn(true);
+    when(itsFacade.exists("42")).thenReturn(true);
 
     ret = ivc.onCommitReceived(event);
 
     assertEmptyList(ret);
+
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(issueExtractor).getIssueIds("bug#4711, bug#42");
+    verifyOneOrMore(itsFacade).exists("4711");
+    verifyOneOrMore(itsFacade).exists("42");
   }
 
   public void testSuggestedMatchingMultipleOneNonExsting()
       throws CommitValidationException, IOException {
     List<CommitValidationMessage> ret;
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("bug#4711, bug#42");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.SUGGESTED)
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("bug#4711, bug#42").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("bug#4711, bug#42"))
-        .andReturn(new String[] {"4711", "42"})
-        .atLeastOnce();
-    expect(itsFacadeFactory.getFacade(project.getNameKey())).andReturn(itsFacade).anyTimes();
-    expect(itsFacade.exists("4711")).andReturn(false).atLeastOnce();
-    expect(itsFacade.exists("42")).andReturn(true).atLeastOnce();
-    replayMocks();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.SUGGESTED);
+    when(issueExtractor.getIssueIds("bug#4711, bug#42")).thenReturn(new String[] {"4711", "42"});
+    when(itsFacadeFactory.getFacade(project.getNameKey())).thenReturn(itsFacade);
+    when(itsFacade.exists("4711")).thenReturn(false);
+    when(itsFacade.exists("42")).thenReturn(true);
 
     ret = ivc.onCommitReceived(event);
 
@@ -340,61 +291,48 @@
     assertFalse(
         "First CommitValidationMessages contains '42', although " + "that bug exists",
         ret.get(0).getMessage().contains("42"));
+
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(issueExtractor).getIssueIds("bug#4711, bug#42");
+    verifyOneOrMore(itsFacade).exists("4711");
+    verifyOneOrMore(itsFacade).exists("42");
   }
 
   public void testMandatoryMatchingMultipleOneNonExsting() throws IOException {
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("bug#4711, bug#42");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.MANDATORY)
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("bug#4711, bug#42").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("bug#4711, bug#42"))
-        .andReturn(new String[] {"4711", "42"})
-        .atLeastOnce();
-    expect(itsFacadeFactory.getFacade(project.getNameKey())).andReturn(itsFacade).anyTimes();
-    expect(itsFacade.exists("4711")).andReturn(false).atLeastOnce();
-    expect(itsFacade.exists("42")).andReturn(true).atLeastOnce();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.MANDATORY);
+    when(issueExtractor.getIssueIds("bug#4711, bug#42")).thenReturn(new String[] {"4711", "42"});
+    when(itsFacadeFactory.getFacade(project.getNameKey())).thenReturn(itsFacade);
+    when(itsFacade.exists("4711")).thenReturn(false);
+    when(itsFacade.exists("42")).thenReturn(true);
 
-    replayMocks();
+    CommitValidationException thrown =
+        assertThrows(CommitValidationException.class, () -> ivc.onCommitReceived(event));
+    assertThat(thrown).hasMessageThat().contains("Non-existing");
 
-    try {
-      ivc.onCommitReceived(event);
-      fail("onCommitReceived did not throw any exception");
-    } catch (CommitValidationException e) {
-      assertTrue(
-          "Message of thrown CommitValidationException does not " + "contain 'Non-existing'",
-          e.getMessage().contains("Non-existing"));
-    }
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(issueExtractor).getIssueIds("bug#4711, bug#42");
+    verifyOneOrMore(itsFacade).exists("4711");
+    verifyOneOrMore(itsFacade).exists("42");
   }
 
   public void testSuggestedMatchingMultipleSomeNonExsting()
       throws CommitValidationException, IOException {
     List<CommitValidationMessage> ret;
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("bug#4711, bug#42");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.SUGGESTED)
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("bug#4711, bug#42").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("bug#4711, bug#42"))
-        .andReturn(new String[] {"4711", "42"})
-        .atLeastOnce();
-    expect(itsFacadeFactory.getFacade(project.getNameKey())).andReturn(itsFacade).anyTimes();
-    expect(itsFacade.exists("4711")).andReturn(false).atLeastOnce();
-    expect(itsFacade.exists("42")).andReturn(false).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.SUGGESTED);
+    when(issueExtractor.getIssueIds("bug#4711, bug#42")).thenReturn(new String[] {"4711", "42"});
+    when(itsFacadeFactory.getFacade(project.getNameKey())).thenReturn(itsFacade);
+    when(itsFacade.exists("4711")).thenReturn(false);
+    when(itsFacade.exists("42")).thenReturn(false);
 
     ret = ivc.onCommitReceived(event);
 
@@ -408,61 +346,48 @@
     assertTrue(
         "First CommitValidationMessages does not contain '42'",
         ret.get(0).getMessage().contains("42"));
+
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(issueExtractor).getIssueIds("bug#4711, bug#42");
+    verifyOneOrMore(itsFacade).exists("4711");
+    verifyOneOrMore(itsFacade).exists("42");
   }
 
   public void testMandatoryMatchingMultipleSomeNonExsting() throws IOException {
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("bug#4711, bug#42");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.MANDATORY)
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("bug#4711, bug#42").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("bug#4711, bug#42"))
-        .andReturn(new String[] {"4711", "42"})
-        .atLeastOnce();
-    expect(itsFacadeFactory.getFacade(project.getNameKey())).andReturn(itsFacade).anyTimes();
-    expect(itsFacade.exists("4711")).andReturn(false).atLeastOnce();
-    expect(itsFacade.exists("42")).andReturn(true).atLeastOnce();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.MANDATORY);
+    when(issueExtractor.getIssueIds("bug#4711, bug#42")).thenReturn(new String[] {"4711", "42"});
+    when(itsFacadeFactory.getFacade(project.getNameKey())).thenReturn(itsFacade);
+    when(itsFacade.exists("4711")).thenReturn(false);
+    when(itsFacade.exists("42")).thenReturn(true);
 
-    replayMocks();
+    CommitValidationException thrown =
+        assertThrows(CommitValidationException.class, () -> ivc.onCommitReceived(event));
+    assertThat(thrown).hasMessageThat().contains("Non-existing");
 
-    try {
-      ivc.onCommitReceived(event);
-      fail("onCommitReceived did not throw any exception");
-    } catch (CommitValidationException e) {
-      assertTrue(
-          "Message of thrown CommitValidationException does not " + "contain 'Non-existing'",
-          e.getMessage().contains("Non-existing"));
-    }
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(issueExtractor).getIssueIds("bug#4711, bug#42");
+    verifyOneOrMore(itsFacade).exists("4711");
+    verifyOneOrMore(itsFacade).exists("42");
   }
 
   public void testSuggestedMatchingMultipleIOExceptionIsNonExsting()
       throws CommitValidationException, IOException {
     List<CommitValidationMessage> ret;
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("bug#4711, bug#42");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.SUGGESTED)
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("bug#4711, bug#42").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("bug#4711, bug#42"))
-        .andReturn(new String[] {"4711", "42"})
-        .atLeastOnce();
-    expect(itsFacadeFactory.getFacade(project.getNameKey())).andReturn(itsFacade).anyTimes();
-    expect(itsFacade.exists("4711")).andThrow(new IOException("InjectedEx1")).atLeastOnce();
-    expect(itsFacade.exists("42")).andReturn(false).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.SUGGESTED);
+    when(issueExtractor.getIssueIds("bug#4711, bug#42")).thenReturn(new String[] {"4711", "42"});
+    when(itsFacadeFactory.getFacade(project.getNameKey())).thenReturn(itsFacade);
+    doThrow(new IOException("InjectedEx1")).when(itsFacade).exists("4711");
+    when(itsFacade.exists("42")).thenReturn(false);
 
     ret = ivc.onCommitReceived(event);
 
@@ -488,27 +413,25 @@
         ret.get(1).getMessage().contains("42"));
 
     assertLogMessageContains("4711");
+
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(issueExtractor).getIssueIds("bug#4711, bug#42");
+    verifyOneOrMore(itsFacade).exists("4711");
+    verifyOneOrMore(itsFacade).exists("42");
   }
 
   public void testMandatoryMatchingSingleIOException()
       throws CommitValidationException, IOException {
     List<CommitValidationMessage> ret;
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("bug#4711");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.MANDATORY)
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("bug#4711").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("bug#4711")).andReturn(new String[] {"4711"}).atLeastOnce();
-    expect(itsFacadeFactory.getFacade(project.getNameKey())).andReturn(itsFacade).anyTimes();
-    expect(itsFacade.exists("4711")).andThrow(new IOException("InjectedEx1")).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.MANDATORY);
+    when(issueExtractor.getIssueIds("bug#4711")).thenReturn(new String[] {"4711"});
+    when(itsFacadeFactory.getFacade(project.getNameKey())).thenReturn(itsFacade);
+    doThrow(new IOException("InjectedEx1")).when(itsFacade).exists("4711");
 
     ret = ivc.onCommitReceived(event);
 
@@ -524,29 +447,23 @@
         ret.get(0).getMessage().contains("InjectedEx1"));
 
     assertLogMessageContains("4711");
+
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(issueExtractor).getIssueIds("bug#4711");
+    verifyOneOrMore(itsFacade).exists("4711");
   }
 
   public void testMandatoryMatchingMultipleIOExceptionIsNonExisting() throws IOException {
-    List<CommitValidationMessage> ret;
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("bug#4711, bug#42");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.MANDATORY)
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("bug#4711, bug#42").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("bug#4711, bug#42"))
-        .andReturn(new String[] {"4711", "42"})
-        .atLeastOnce();
-    expect(itsFacadeFactory.getFacade(project.getNameKey())).andReturn(itsFacade).anyTimes();
-    expect(itsFacade.exists("4711")).andThrow(new IOException("InjectedEx1")).atLeastOnce();
-    expect(itsFacade.exists("42")).andReturn(false).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.MANDATORY);
+    when(issueExtractor.getIssueIds("bug#4711, bug#42")).thenReturn(new String[] {"4711", "42"});
+    when(itsFacadeFactory.getFacade(project.getNameKey())).thenReturn(itsFacade);
+    doThrow(new IOException("InjectedEx1")).when(itsFacade).exists("4711");
+    when(itsFacade.exists("42")).thenReturn(false);
 
     try {
       ivc.onCommitReceived(event);
@@ -557,30 +474,26 @@
           "Message of thrown CommitValidationException does not " + "contain 'Non-existing'",
           e.getMessage().contains("Non-existing"));
     }
+
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(issueExtractor).getIssueIds("bug#4711, bug#42");
+    verifyOneOrMore(itsFacade).exists("4711");
+    verifyOneOrMore(itsFacade).exists("42");
   }
 
   public void testMandatoryMatchingMultipleIOExceptionExisting()
       throws CommitValidationException, IOException {
     List<CommitValidationMessage> ret;
     ItsValidateComment ivc = injector.getInstance(ItsValidateComment.class);
-    ReceiveCommand command = createMock(ReceiveCommand.class);
-    RevCommit commit = createMock(RevCommit.class);
+    ReceiveCommand command = mock(ReceiveCommand.class);
+    RevCommit commit = createCommit("bug#4711, bug#42");
     CommitReceivedEvent event = newCommitReceivedEvent(command, project, null, commit, null);
 
-    expect(itsConfig.getItsAssociationPolicy())
-        .andReturn(ItsAssociationPolicy.MANDATORY)
-        .atLeastOnce();
-    expect(commit.getFullMessage()).andReturn("bug#4711, bug#42").atLeastOnce();
-    expect(commit.getId()).andReturn(commit).anyTimes();
-    expect(commit.getName()).andReturn("TestCommit").anyTimes();
-    expect(issueExtractor.getIssueIds("bug#4711, bug#42"))
-        .andReturn(new String[] {"4711", "42"})
-        .atLeastOnce();
-    expect(itsFacadeFactory.getFacade(project.getNameKey())).andReturn(itsFacade).anyTimes();
-    expect(itsFacade.exists("4711")).andThrow(new IOException("InjectedEx1")).atLeastOnce();
-    expect(itsFacade.exists("42")).andReturn(true).atLeastOnce();
-
-    replayMocks();
+    when(itsConfig.getItsAssociationPolicy()).thenReturn(ItsAssociationPolicy.MANDATORY);
+    when(issueExtractor.getIssueIds("bug#4711, bug#42")).thenReturn(new String[] {"4711", "42"});
+    when(itsFacadeFactory.getFacade(project.getNameKey())).thenReturn(itsFacade);
+    doThrow(new IOException("InjectedEx1")).when(itsFacade).exists("4711");
+    when(itsFacade.exists("42")).thenReturn(true);
 
     ret = ivc.onCommitReceived(event);
 
@@ -596,6 +509,11 @@
         ret.get(0).getMessage().contains("InjectedEx1"));
 
     assertLogMessageContains("4711");
+
+    verifyOneOrMore(itsConfig).getItsAssociationPolicy();
+    verifyOneOrMore(issueExtractor).getIssueIds("bug#4711, bug#42");
+    verifyOneOrMore(itsFacade).exists("4711");
+    verifyOneOrMore(itsFacade).exists("42");
   }
 
   public void assertEmptyList(List<CommitValidationMessage> list) {
@@ -611,9 +529,9 @@
   }
 
   private void setupCommonMocks() {
-    expect(itsConfig.getIssuePattern()).andReturn(Pattern.compile("bug#(\\d+)")).anyTimes();
-    Project.NameKey projectNK = new Project.NameKey("myProject");
-    expect(itsConfig.isEnabled(projectNK, null)).andReturn(true).anyTimes();
+    when(itsConfig.getIssuePattern()).thenReturn(Pattern.compile("bug#(\\d+)"));
+    Project.NameKey projectNK = Project.nameKey("myProject");
+    when(itsConfig.isEnabled(projectNK, null)).thenReturn(true);
   }
 
   @Override
@@ -631,32 +549,56 @@
       String refName,
       RevCommit commit,
       IdentifiedUser user) {
-    CommitReceivedEvent event = createMock(CommitReceivedEvent.class);
+    CommitReceivedEvent event = mock(CommitReceivedEvent.class);
     event.command = command;
     event.project = project;
     event.refName = refName;
     event.commit = commit;
     event.user = user;
-    expect(event.getProjectNameKey()).andReturn(project.getNameKey()).anyTimes();
-    expect(event.getRefName()).andReturn(null).anyTimes();
+    when(event.getProjectNameKey()).thenReturn(project.getNameKey());
+    when(event.getRefName()).thenReturn(null);
     return event;
   }
 
+  private RevCommit createCommit() {
+    return createCommit("Hello world");
+  }
+
+  private RevCommit createCommit(String fullMessage) {
+    String parents = String.format("parent %040x\n", new java.util.Random().nextLong());
+    String commitData =
+        String.format(
+            "tree %040x\n"
+                + parents
+                + "author John Doe <john@doe.com> %d +0100\n"
+                + "committer John Doe <john@doe.com> %d +0100\n\n"
+                + "%s",
+            new Random().nextLong(),
+            new Date().getTime(),
+            new Date().getTime(),
+            fullMessage);
+    return RevCommit.parse(commitData.getBytes());
+  }
+
+  private <T> T verifyOneOrMore(T mock) {
+    return verify(mock, atLeastOnce());
+  }
+
   private class TestModule extends FactoryModule {
     @Override
     protected void configure() {
       bind(String.class).annotatedWith(PluginName.class).toInstance("ItsTestName");
 
-      issueExtractor = createMock(IssueExtractor.class);
+      issueExtractor = mock(IssueExtractor.class);
       bind(IssueExtractor.class).toInstance(issueExtractor);
 
-      itsFacade = createMock(ItsFacade.class);
+      itsFacade = mock(ItsFacade.class);
       bind(ItsFacade.class).toInstance(itsFacade);
 
-      itsConfig = createMock(ItsConfig.class);
+      itsConfig = mock(ItsConfig.class);
       bind(ItsConfig.class).toInstance(itsConfig);
 
-      itsFacadeFactory = createMock(ItsFacadeFactory.class);
+      itsFacadeFactory = mock(ItsFacadeFactory.class);
       bind(ItsFacadeFactory.class).toInstance(itsFacadeFactory);
     }
   }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionControllerTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionControllerTest.java
index bd32089..3653d26 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionControllerTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionControllerTest.java
@@ -13,8 +13,10 @@
 // limitations under the License.
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.expect;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -44,14 +46,11 @@
   public void testNoPropertySets() {
     ActionController actionController = createActionController();
 
-    ChangeEvent event = createMock(ChangeEvent.class);
+    ChangeEvent event = mock(ChangeEvent.class);
 
     Set<Map<String, String>> propertySets = new HashSet<>();
-    expect(propertyExtractor.extractFrom(event))
-        .andReturn(new RefEventProperties(Collections.emptyMap(), propertySets))
-        .anyTimes();
-
-    replayMocks();
+    when(propertyExtractor.extractFrom(event))
+        .thenReturn(new RefEventProperties(Collections.emptyMap(), propertySets));
 
     actionController.onEvent(event);
   }
@@ -59,22 +58,22 @@
   public void testNoActionsOrNoIssues() {
     ActionController actionController = createActionController();
 
-    ChangeEvent event = createMock(ChangeEvent.class);
+    ChangeEvent event = mock(ChangeEvent.class);
 
     Set<Map<String, String>> propertySets = new HashSet<>();
     Map<String, String> properties = ImmutableMap.of("fake", "property");
     propertySets.add(properties);
 
-    expect(propertyExtractor.extractFrom(event))
-        .andReturn(new RefEventProperties(properties, propertySets))
-        .anyTimes();
+    when(propertyExtractor.extractFrom(event))
+        .thenReturn(new RefEventProperties(properties, propertySets));
 
     // When no issues are found in the commit message, the list of actions is empty
     // as there are no matchs with an empty map of properties.
     Collection<ActionRequest> actions = Collections.emptySet();
-    expect(ruleBase.actionRequestsFor(properties)).andReturn(actions).times(2);
-
-    replayMocks();
+    when(ruleBase.actionRequestsFor(properties))
+        .thenReturn(actions)
+        .thenReturn(actions)
+        .thenThrow(new UnsupportedOperationException("Method called more than twice"));
 
     actionController.onEvent(event);
   }
@@ -82,7 +81,7 @@
   public void testSinglePropertyMapSingleIssueActionSingleProjectAction() {
     ActionController actionController = createActionController();
 
-    ChangeEvent event = createMock(ChangeEvent.class);
+    ChangeEvent event = mock(ChangeEvent.class);
 
     Map<String, String> projectProperties = ImmutableMap.of("its-project", "itsProject");
 
@@ -94,56 +93,58 @@
 
     Set<Map<String, String>> propertySets = ImmutableSet.of(issueProperties);
 
-    expect(propertyExtractor.extractFrom(event))
-        .andReturn(new RefEventProperties(projectProperties, propertySets))
-        .anyTimes();
+    when(propertyExtractor.extractFrom(event))
+        .thenReturn(new RefEventProperties(projectProperties, propertySets));
 
-    ActionRequest issueActionRequest1 = createMock(ActionRequest.class);
+    ActionRequest issueActionRequest1 = mock(ActionRequest.class);
     Collection<ActionRequest> issueActionRequests = ImmutableList.of(issueActionRequest1);
-    expect(ruleBase.actionRequestsFor(issueProperties)).andReturn(issueActionRequests).once();
+    when(ruleBase.actionRequestsFor(issueProperties))
+        .thenReturn(issueActionRequests)
+        .thenThrow(new UnsupportedOperationException("Method called more than once"));
 
-    ActionRequest projectActionRequest1 = createMock(ActionRequest.class);
+    ActionRequest projectActionRequest1 = mock(ActionRequest.class);
     Collection<ActionRequest> projectActionRequests = ImmutableList.of(projectActionRequest1);
-    expect(ruleBase.actionRequestsFor(projectProperties)).andReturn(projectActionRequests).once();
-
-    actionExecutor.executeOnIssue(issueActionRequests, issueProperties);
-    actionExecutor.executeOnProject(projectActionRequests, projectProperties);
-
-    replayMocks();
+    when(ruleBase.actionRequestsFor(projectProperties))
+        .thenReturn(projectActionRequests)
+        .thenThrow(new UnsupportedOperationException("Method called more than once"));
 
     actionController.onEvent(event);
+
+    verify(actionExecutor).executeOnIssue(issueActionRequests, issueProperties);
+    verify(actionExecutor).executeOnProject(projectActionRequests, projectProperties);
   }
 
   public void testMultiplePropertyMapsMultipleActionMultipleIssue() {
     ActionController actionController = createActionController();
 
-    ChangeEvent event = createMock(ChangeEvent.class);
+    ChangeEvent event = mock(ChangeEvent.class);
 
     Map<String, String> properties1 = ImmutableMap.of("issue", "testIssue");
     Map<String, String> properties2 = ImmutableMap.of("issue", "testIssue2");
 
     Set<Map<String, String>> propertySets = ImmutableSet.of(properties1, properties2);
 
-    expect(propertyExtractor.extractFrom(event))
-        .andReturn(new RefEventProperties(Collections.emptyMap(), propertySets))
-        .anyTimes();
+    when(propertyExtractor.extractFrom(event))
+        .thenReturn(new RefEventProperties(Collections.emptyMap(), propertySets));
 
-    ActionRequest actionRequest1 = createMock(ActionRequest.class);
+    ActionRequest actionRequest1 = mock(ActionRequest.class);
     Collection<ActionRequest> actionRequests1 = ImmutableList.of(actionRequest1);
 
-    ActionRequest actionRequest2 = createMock(ActionRequest.class);
-    ActionRequest actionRequest3 = createMock(ActionRequest.class);
+    ActionRequest actionRequest2 = mock(ActionRequest.class);
+    ActionRequest actionRequest3 = mock(ActionRequest.class);
     Collection<ActionRequest> actionRequests2 = ImmutableList.of(actionRequest2, actionRequest3);
 
-    expect(ruleBase.actionRequestsFor(properties1)).andReturn(actionRequests1).once();
-    expect(ruleBase.actionRequestsFor(properties2)).andReturn(actionRequests2).once();
-
-    actionExecutor.executeOnIssue(actionRequests1, properties1);
-    actionExecutor.executeOnIssue(actionRequests2, properties2);
-
-    replayMocks();
+    when(ruleBase.actionRequestsFor(properties1))
+        .thenReturn(actionRequests1)
+        .thenThrow(new UnsupportedOperationException("Method called more than once"));
+    when(ruleBase.actionRequestsFor(properties2))
+        .thenReturn(actionRequests2)
+        .thenThrow(new UnsupportedOperationException("Method called more than once"));
 
     actionController.onEvent(event);
+
+    verify(actionExecutor).executeOnIssue(actionRequests1, properties1);
+    verify(actionExecutor).executeOnIssue(actionRequests2, properties2);
   }
 
   private ActionController createActionController() {
@@ -151,7 +152,7 @@
   }
 
   private void setupCommonMocks() {
-    expect(itsConfig.isEnabled(anyObject(RefEvent.class))).andReturn(true).anyTimes();
+    when(itsConfig.isEnabled(any(RefEvent.class))).thenReturn(true);
   }
 
   @Override
@@ -165,16 +166,16 @@
   private class TestModule extends FactoryModule {
     @Override
     protected void configure() {
-      propertyExtractor = createMock(PropertyExtractor.class);
+      propertyExtractor = mock(PropertyExtractor.class);
       bind(PropertyExtractor.class).toInstance(propertyExtractor);
 
-      ruleBase = createMock(RuleBase.class);
+      ruleBase = mock(RuleBase.class);
       bind(RuleBase.class).toInstance(ruleBase);
 
-      actionExecutor = createMock(ActionExecutor.class);
+      actionExecutor = mock(ActionExecutor.class);
       bind(ActionExecutor.class).toInstance(actionExecutor);
 
-      itsConfig = createMock(ItsConfig.class);
+      itsConfig = mock(ItsConfig.class);
       bind(ItsConfig.class).toInstance(itsConfig);
     }
   }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutorTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutorTest.java
index e82ffd1..5b8c43f 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutorTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionExecutorTest.java
@@ -13,15 +13,17 @@
 // limitations under the License.
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.entities.Project;
 import com.google.gerrit.extensions.annotations.Exports;
 import com.google.gerrit.extensions.config.FactoryModule;
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.reviewdb.client.Project;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.googlesource.gerrit.plugins.its.base.its.ItsFacade;
@@ -57,35 +59,30 @@
           .build();
 
   public void testExecuteItem() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getName()).andReturn("unparsed");
-    expect(actionRequest.getUnparsed()).andReturn("unparsed action 1");
-    expect(itsFacadeFactory.getFacade(new Project.NameKey(properties.get("project"))))
-        .andReturn(its);
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getName()).thenReturn("unparsed");
+    when(actionRequest.getUnparsed()).thenReturn("unparsed action 1");
+    when(itsFacadeFactory.getFacade(Project.nameKey(properties.get("project")))).thenReturn(its);
 
     Set<ActionRequest> actionRequests = ImmutableSet.of(actionRequest);
 
-    its.performAction("4711", "unparsed action 1");
-
-    replayMocks();
-
     ActionExecutor actionExecutor = createActionExecutor();
     actionExecutor.executeOnIssue(actionRequests, properties);
+
+    verify(its).performAction("4711", "unparsed action 1");
   }
 
   public void testExecuteItemException() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getName()).andReturn("unparsed");
-    expect(actionRequest.getUnparsed()).andReturn("unparsed action 1");
-    expect(itsFacadeFactory.getFacade(new Project.NameKey(properties.get("project"))))
-        .andReturn(its);
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getName()).thenReturn("unparsed");
+    when(actionRequest.getUnparsed()).thenReturn("unparsed action 1");
+    when(itsFacadeFactory.getFacade(Project.nameKey(properties.get("project")))).thenReturn(its);
 
     Set<ActionRequest> actionRequests = ImmutableSet.of(actionRequest);
 
-    its.performAction("4711", "unparsed action 1");
-    expectLastCall().andThrow(new IOException("injected exception 1"));
-
-    replayMocks();
+    doThrow(new IOException("injected exception 1"))
+        .when(its)
+        .performAction("4711", "unparsed action 1");
 
     ActionExecutor actionExecutor = createActionExecutor();
     actionExecutor.executeOnIssue(actionRequests, properties);
@@ -94,209 +91,180 @@
   }
 
   public void testExecuteIterable() throws IOException {
-    ActionRequest actionRequest1 = createMock(ActionRequest.class);
-    expect(actionRequest1.getName()).andReturn("unparsed");
-    expect(actionRequest1.getUnparsed()).andReturn("unparsed action 1");
+    ActionRequest actionRequest1 = mock(ActionRequest.class);
+    when(actionRequest1.getName()).thenReturn("unparsed");
+    when(actionRequest1.getUnparsed()).thenReturn("unparsed action 1");
 
-    ActionRequest actionRequest2 = createMock(ActionRequest.class);
-    expect(actionRequest2.getName()).andReturn("unparsed");
-    expect(actionRequest2.getUnparsed()).andReturn("unparsed action 2");
-    expect(itsFacadeFactory.getFacade(new Project.NameKey(properties.get("project"))))
-        .andReturn(its)
-        .anyTimes();
+    ActionRequest actionRequest2 = mock(ActionRequest.class);
+    when(actionRequest2.getName()).thenReturn("unparsed");
+    when(actionRequest2.getUnparsed()).thenReturn("unparsed action 2");
+    when(itsFacadeFactory.getFacade(Project.nameKey(properties.get("project")))).thenReturn(its);
 
     Set<ActionRequest> actionRequests = ImmutableSet.of(actionRequest1, actionRequest2);
 
-    its.performAction("4711", "unparsed action 1");
-    its.performAction("4711", "unparsed action 2");
-
-    replayMocks();
-
     ActionExecutor actionExecutor = createActionExecutor();
     actionExecutor.executeOnIssue(actionRequests, properties);
+
+    verify(its).performAction("4711", "unparsed action 1");
+    verify(its).performAction("4711", "unparsed action 2");
   }
 
   public void testExecuteIterableExceptions() throws IOException {
-    ActionRequest actionRequest1 = createMock(ActionRequest.class);
-    expect(actionRequest1.getName()).andReturn("unparsed");
-    expect(actionRequest1.getUnparsed()).andReturn("unparsed action 1");
+    ActionRequest actionRequest1 = mock(ActionRequest.class);
+    when(actionRequest1.getName()).thenReturn("unparsed");
+    when(actionRequest1.getUnparsed()).thenReturn("unparsed action 1");
 
-    ActionRequest actionRequest2 = createMock(ActionRequest.class);
-    expect(actionRequest2.getName()).andReturn("unparsed");
-    expect(actionRequest2.getUnparsed()).andReturn("unparsed action 2");
+    ActionRequest actionRequest2 = mock(ActionRequest.class);
+    when(actionRequest2.getName()).thenReturn("unparsed");
+    when(actionRequest2.getUnparsed()).thenReturn("unparsed action 2");
 
-    ActionRequest actionRequest3 = createMock(ActionRequest.class);
-    expect(actionRequest3.getName()).andReturn("unparsed");
-    expect(actionRequest3.getUnparsed()).andReturn("unparsed action 3");
-    expect(itsFacadeFactory.getFacade(new Project.NameKey(properties.get("project"))))
-        .andReturn(its)
-        .anyTimes();
+    ActionRequest actionRequest3 = mock(ActionRequest.class);
+    when(actionRequest3.getName()).thenReturn("unparsed");
+    when(actionRequest3.getUnparsed()).thenReturn("unparsed action 3");
+    when(itsFacadeFactory.getFacade(Project.nameKey(properties.get("project")))).thenReturn(its);
 
     Set<ActionRequest> actionRequests =
         ImmutableSet.of(actionRequest1, actionRequest2, actionRequest3);
 
-    its.performAction("4711", "unparsed action 1");
-    expectLastCall().andThrow(new IOException("injected exception 1"));
-    its.performAction("4711", "unparsed action 2");
-    its.performAction("4711", "unparsed action 3");
-    expectLastCall().andThrow(new IOException("injected exception 3"));
-
-    replayMocks();
+    doThrow(new IOException("injected exception 1"))
+        .when(its)
+        .performAction("4711", "unparsed action 1");
+    doThrow(new IOException("injected exception 3"))
+        .when(its)
+        .performAction("4711", "unparsed action 3");
 
     ActionExecutor actionExecutor = createActionExecutor();
     actionExecutor.executeOnIssue(actionRequests, properties);
 
     assertLogThrowableMessageContains("injected exception 1");
     assertLogThrowableMessageContains("injected exception 3");
+
+    verify(its).performAction("4711", "unparsed action 2");
   }
 
   public void testAddCommentDelegation() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getName()).andReturn("add-comment");
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getName()).thenReturn("add-comment");
 
     Set<ActionRequest> actionRequests = ImmutableSet.of(actionRequest);
 
-    AddComment addComment = createMock(AddComment.class);
-    expect(addCommentFactory.create()).andReturn(addComment);
-    expect(itsFacadeFactory.getFacade(new Project.NameKey(properties.get("project"))))
-        .andReturn(its);
-
-    addComment.execute(its, "4711", actionRequest, properties);
-
-    replayMocks();
+    AddComment addComment = mock(AddComment.class);
+    when(addCommentFactory.create()).thenReturn(addComment);
+    when(itsFacadeFactory.getFacade(Project.nameKey(properties.get("project")))).thenReturn(its);
 
     ActionExecutor actionExecutor = createActionExecutor();
     actionExecutor.executeOnIssue(actionRequests, properties);
+
+    verify(addComment).execute(its, "4711", actionRequest, properties);
   }
 
   public void testAddSoyCommentDelegation() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getName()).andReturn("add-soy-comment");
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getName()).thenReturn("add-soy-comment");
 
     Set<ActionRequest> actionRequests = ImmutableSet.of(actionRequest);
 
-    AddSoyComment addSoyComment = createMock(AddSoyComment.class);
-    expect(addSoyCommentFactory.create()).andReturn(addSoyComment);
-    expect(itsFacadeFactory.getFacade(new Project.NameKey(properties.get("project"))))
-        .andReturn(its);
-
-    addSoyComment.execute(its, "4711", actionRequest, properties);
-
-    replayMocks();
+    AddSoyComment addSoyComment = mock(AddSoyComment.class);
+    when(addSoyCommentFactory.create()).thenReturn(addSoyComment);
+    when(itsFacadeFactory.getFacade(Project.nameKey(properties.get("project")))).thenReturn(its);
 
     ActionExecutor actionExecutor = createActionExecutor();
     actionExecutor.executeOnIssue(actionRequests, properties);
+
+    verify(addSoyComment).execute(its, "4711", actionRequest, properties);
   }
 
   public void testAddStandardCommentDelegation() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getName()).andReturn("add-standard-comment");
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getName()).thenReturn("add-standard-comment");
 
     Set<ActionRequest> actionRequests = ImmutableSet.of(actionRequest);
 
-    AddStandardComment addStandardComment = createMock(AddStandardComment.class);
-    expect(addStandardCommentFactory.create()).andReturn(addStandardComment);
-    expect(itsFacadeFactory.getFacade(new Project.NameKey(properties.get("project"))))
-        .andReturn(its);
-
-    addStandardComment.execute(its, "4711", actionRequest, properties);
-
-    replayMocks();
+    AddStandardComment addStandardComment = mock(AddStandardComment.class);
+    when(addStandardCommentFactory.create()).thenReturn(addStandardComment);
+    when(itsFacadeFactory.getFacade(Project.nameKey(properties.get("project")))).thenReturn(its);
 
     ActionExecutor actionExecutor = createActionExecutor();
     actionExecutor.executeOnIssue(actionRequests, properties);
+
+    verify(addStandardComment).execute(its, "4711", actionRequest, properties);
   }
 
   public void testLogEventDelegation() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getName()).andReturn("log-event");
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getName()).thenReturn("log-event");
 
     Set<ActionRequest> actionRequests = ImmutableSet.of(actionRequest);
 
-    LogEvent logEvent = createMock(LogEvent.class);
-    expect(logEventFactory.create()).andReturn(logEvent);
-    expect(itsFacadeFactory.getFacade(new Project.NameKey(properties.get("project"))))
-        .andReturn(its);
-
-    logEvent.execute(its, "4711", actionRequest, properties);
-
-    replayMocks();
+    LogEvent logEvent = mock(LogEvent.class);
+    when(logEventFactory.create()).thenReturn(logEvent);
+    when(itsFacadeFactory.getFacade(Project.nameKey(properties.get("project")))).thenReturn(its);
 
     ActionExecutor actionExecutor = createActionExecutor();
     actionExecutor.executeOnIssue(actionRequests, properties);
+
+    verify(logEvent).execute(its, "4711", actionRequest, properties);
   }
 
   public void testCreateVersionFromPropertyDelegation() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getName()).andReturn("create-version-from-property");
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getName()).thenReturn("create-version-from-property");
 
-    CreateVersionFromProperty createVersionFromProperty =
-        createMock(CreateVersionFromProperty.class);
-    expect(createVersionFromPropertyFactory.create()).andReturn(createVersionFromProperty);
-    expect(itsFacadeFactory.getFacade(new Project.NameKey(properties.get("project"))))
-        .andReturn(its);
-
-    createVersionFromProperty.execute(its, "itsTestProject", actionRequest, projectProperties);
-
-    replayMocks();
+    CreateVersionFromProperty createVersionFromProperty = mock(CreateVersionFromProperty.class);
+    when(createVersionFromPropertyFactory.create()).thenReturn(createVersionFromProperty);
+    when(itsFacadeFactory.getFacade(Project.nameKey(properties.get("project")))).thenReturn(its);
 
     ActionExecutor actionExecutor = createActionExecutor();
     actionExecutor.executeOnProject(Collections.singleton(actionRequest), projectProperties);
+
+    verify(createVersionFromProperty)
+        .execute(its, "itsTestProject", actionRequest, projectProperties);
   }
 
   public void testAddPropertyToFieldDelegation() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getName()).andReturn("add-property-to-field");
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getName()).thenReturn("add-property-to-field");
 
     Set<ActionRequest> actionRequests = ImmutableSet.of(actionRequest);
 
-    AddPropertyToField addPropertyToField = createMock(AddPropertyToField.class);
-    expect(addPropertyToFieldFactory.create()).andReturn(addPropertyToField);
-    expect(itsFacadeFactory.getFacade(new Project.NameKey(properties.get("project"))))
-        .andReturn(its);
-
-    addPropertyToField.execute(its, "4711", actionRequest, properties);
-
-    replayMocks();
+    AddPropertyToField addPropertyToField = mock(AddPropertyToField.class);
+    when(addPropertyToFieldFactory.create()).thenReturn(addPropertyToField);
+    when(itsFacadeFactory.getFacade(Project.nameKey(properties.get("project")))).thenReturn(its);
 
     ActionExecutor actionExecutor = createActionExecutor();
     actionExecutor.executeOnIssue(actionRequests, properties);
+
+    verify(addPropertyToField).execute(its, "4711", actionRequest, properties);
   }
 
   public void testExecuteIssueCustomAction() throws IOException {
-    expect(customAction.getType()).andReturn(ActionType.ISSUE);
+    when(customAction.getType()).thenReturn(ActionType.ISSUE);
 
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getName()).andReturn(CUSTOM_ACTION_NAME);
-    expect(itsFacadeFactory.getFacade(new Project.NameKey(properties.get("project"))))
-        .andReturn(its);
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getName()).thenReturn(CUSTOM_ACTION_NAME);
+    when(itsFacadeFactory.getFacade(Project.nameKey(properties.get("project")))).thenReturn(its);
 
     Set<ActionRequest> actionRequests = ImmutableSet.of(actionRequest);
 
-    customAction.execute(its, "4711", actionRequest, properties);
-
-    replayMocks();
-
     ActionExecutor actionExecutor = createActionExecutor();
     actionExecutor.executeOnIssue(actionRequests, properties);
+
+    verify(customAction).execute(its, "4711", actionRequest, properties);
   }
 
   public void testExecuteProjectCustomAction() throws IOException {
-    expect(customAction.getType()).andReturn(ActionType.PROJECT);
+    when(customAction.getType()).thenReturn(ActionType.PROJECT);
 
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getName()).andReturn(CUSTOM_ACTION_NAME);
-    expect(itsFacadeFactory.getFacade(new Project.NameKey(properties.get("project"))))
-        .andReturn(its);
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getName()).thenReturn(CUSTOM_ACTION_NAME);
+    when(itsFacadeFactory.getFacade(Project.nameKey(properties.get("project")))).thenReturn(its);
 
     Set<ActionRequest> actionRequests = ImmutableSet.of(actionRequest);
 
-    customAction.execute(its, "itsTestProject", actionRequest, projectProperties);
-
-    replayMocks();
-
     ActionExecutor actionExecutor = createActionExecutor();
     actionExecutor.executeOnProject(actionRequests, projectProperties);
+
+    verify(customAction).execute(its, "itsTestProject", actionRequest, projectProperties);
   }
 
   private ActionExecutor createActionExecutor() {
@@ -312,32 +280,32 @@
   private class TestModule extends FactoryModule {
     @Override
     protected void configure() {
-      its = createMock(ItsFacade.class);
+      its = mock(ItsFacade.class);
       bind(ItsFacade.class).toInstance(its);
 
-      addCommentFactory = createMock(AddComment.Factory.class);
+      addCommentFactory = mock(AddComment.Factory.class);
       bind(AddComment.Factory.class).toInstance(addCommentFactory);
 
-      addSoyCommentFactory = createMock(AddSoyComment.Factory.class);
+      addSoyCommentFactory = mock(AddSoyComment.Factory.class);
       bind(AddSoyComment.Factory.class).toInstance(addSoyCommentFactory);
 
-      addStandardCommentFactory = createMock(AddStandardComment.Factory.class);
+      addStandardCommentFactory = mock(AddStandardComment.Factory.class);
       bind(AddStandardComment.Factory.class).toInstance(addStandardCommentFactory);
 
-      logEventFactory = createMock(LogEvent.Factory.class);
+      logEventFactory = mock(LogEvent.Factory.class);
       bind(LogEvent.Factory.class).toInstance(logEventFactory);
 
-      itsFacadeFactory = createMock(ItsFacadeFactory.class);
+      itsFacadeFactory = mock(ItsFacadeFactory.class);
       bind(ItsFacadeFactory.class).toInstance(itsFacadeFactory);
 
-      addPropertyToFieldFactory = createMock(AddPropertyToField.Factory.class);
+      addPropertyToFieldFactory = mock(AddPropertyToField.Factory.class);
       bind(AddPropertyToField.Factory.class).toInstance(addPropertyToFieldFactory);
 
-      createVersionFromPropertyFactory = createMock(CreateVersionFromProperty.Factory.class);
+      createVersionFromPropertyFactory = mock(CreateVersionFromProperty.Factory.class);
       bind(CreateVersionFromProperty.Factory.class).toInstance(createVersionFromPropertyFactory);
 
       DynamicMap.mapOf(binder(), CustomAction.class);
-      customAction = createMock(CustomAction.class);
+      customAction = mock(CustomAction.class);
 
       bind(CustomAction.class)
           .annotatedWith(Exports.named(CUSTOM_ACTION_NAME))
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionRequestTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionRequestTest.java
index e6de999..ac927f4 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionRequestTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ActionRequestTest.java
@@ -23,135 +23,97 @@
   private Injector injector;
 
   public void testUnparsedParameterless() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action");
     assertEquals("Unparsed string does not match", "action", actionRequest.getUnparsed());
   }
 
   public void testUnparsedNull() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest(null);
     assertEquals("Unparsed string does not match", "", actionRequest.getUnparsed());
   }
 
   public void testUnparsedSingleParameter() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action param");
     assertEquals("Unparsed string does not match", "action param", actionRequest.getUnparsed());
   }
 
   public void testUnparsedMultipleParameters() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action param1 param2");
     assertEquals(
         "Unparsed string does not match", "action param1 param2", actionRequest.getUnparsed());
   }
 
   public void testNameParameterless() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action");
     assertEquals("Unparsed string does not match", "action", actionRequest.getName());
   }
 
   public void testNameSingleParameter() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action param");
     assertEquals("Unparsed string does not match", "action", actionRequest.getName());
   }
 
   public void testNameMultipleParameters() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action param1 param2");
     assertEquals("Unparsed string does not match", "action", actionRequest.getName());
   }
 
   public void testNameNull() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest(null);
     assertEquals("Unparsed string does not match", "", actionRequest.getName());
   }
 
   public void testParameter1Parameterless() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action");
     assertEquals("Unparsed string does not match", "", actionRequest.getParameter(1));
   }
 
   public void testParameter1Null() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest(null);
     assertEquals("Unparsed string does not match", "", actionRequest.getParameter(1));
   }
 
   public void testParameter1SingleParameter() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action param");
     assertEquals("Unparsed string does not match", "param", actionRequest.getParameter(1));
   }
 
   public void testParemeter1MultipleParameters() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action param1 param2");
     assertEquals("Unparsed string does not match", "param1", actionRequest.getParameter(1));
   }
 
   public void testParameter3Parameterless() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action");
     assertEquals("Unparsed string does not match", "", actionRequest.getParameter(3));
   }
 
   public void testParameter3Null() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest(null);
     assertEquals("Unparsed string does not match", "", actionRequest.getParameter(3));
   }
 
   public void testParameter3SingleParameter() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action param");
     assertEquals("Unparsed string does not match", "", actionRequest.getParameter(3));
   }
 
   public void testParemeter3With2Parameters() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action param1 param2");
     assertEquals("Unparsed string does not match", "", actionRequest.getParameter(3));
   }
 
   public void testParemeter3With3Parameters() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action param1 param2 " + "param3");
     assertEquals("Unparsed string does not match", "param3", actionRequest.getParameter(3));
   }
 
   public void testParemeter3With4Parameters() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action param1 param2 " + "param3 param4");
     assertEquals("Unparsed string does not match", "param3", actionRequest.getParameter(3));
   }
 
   public void testParametersParameterless() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action");
 
     String[] expected = new String[0];
@@ -162,8 +124,6 @@
   }
 
   public void testParametersNull() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest(null);
 
     String[] expected = new String[0];
@@ -174,8 +134,6 @@
   }
 
   public void testParametersSingleParameter() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action param");
 
     String[] expected = new String[] {"param"};
@@ -186,8 +144,6 @@
   }
 
   public void testParameters3Parameter() {
-    replayMocks();
-
     ActionRequest actionRequest = createActionRequest("action param1 param2 " + "param3");
 
     String[] expected = new String[] {"param1", "param2", "param3"};
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddCommentTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddCommentTest.java
index 149dfca..87fc762 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddCommentTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddCommentTest.java
@@ -13,7 +13,9 @@
 // limitations under the License.
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
-import static org.easymock.EasyMock.expect;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.gerrit.extensions.config.FactoryModule;
@@ -29,25 +31,21 @@
   private ItsFacade its;
 
   public void testEmpty() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameters()).andReturn(new String[] {});
-
-    replayMocks();
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameters()).thenReturn(new String[] {});
 
     AddComment addComment = createAddComment();
     addComment.execute(null, "4711", actionRequest, ImmutableMap.of());
   }
 
   public void testPlain() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameters()).andReturn(new String[] {"Some", "test", "comment"});
-
-    its.addComment("4711", "Some test comment");
-
-    replayMocks();
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameters()).thenReturn(new String[] {"Some", "test", "comment"});
 
     AddComment addComment = createAddComment();
     addComment.execute(its, "4711", actionRequest, ImmutableMap.of());
+
+    verify(its).addComment("4711", "Some test comment");
   }
 
   private AddComment createAddComment() {
@@ -63,7 +61,7 @@
   private class TestModule extends FactoryModule {
     @Override
     protected void configure() {
-      its = createMock(ItsFacade.class);
+      its = mock(ItsFacade.class);
       bind(ItsFacade.class).toInstance(its);
     }
   }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddPropertyToFieldParametersExtractorTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddPropertyToFieldParametersExtractorTest.java
index fb047f7..a760936 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddPropertyToFieldParametersExtractorTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddPropertyToFieldParametersExtractorTest.java
@@ -14,16 +14,18 @@
 
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
-import static org.easymock.EasyMock.expect;
+import static com.google.common.truth.Truth8.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import com.google.gerrit.extensions.config.FactoryModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
-import com.googlesource.gerrit.plugins.its.base.testutil.MockingTestCase;
 import java.util.Collections;
 import java.util.Optional;
+import junit.framework.TestCase;
 
-public class AddPropertyToFieldParametersExtractorTest extends MockingTestCase {
+public class AddPropertyToFieldParametersExtractorTest extends TestCase {
 
   private static final String FIELD_ID = "fieldId";
   private static final String PROPERTY_ID = "propertyId";
@@ -53,52 +55,40 @@
   }
 
   private void testWrongNumberOfReceivedParameters(String[] parameters) {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameters()).andReturn(parameters);
-
-    replayMocks();
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameters()).thenReturn(parameters);
 
     assertFalse(extractor.extract(actionRequest, Collections.emptyMap()).isPresent());
   }
 
   public void testBlankFieldId() {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameters()).andReturn(new String[] {PROPERTY_ID, ""});
-
-    replayMocks();
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameters()).thenReturn(new String[] {PROPERTY_ID, ""});
 
     assertFalse(extractor.extract(actionRequest, Collections.emptyMap()).isPresent());
   }
 
   public void testBlankPropertyId() {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameters()).andReturn(new String[] {"", FIELD_ID});
-
-    replayMocks();
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameters()).thenReturn(new String[] {"", FIELD_ID});
 
     assertFalse(extractor.extract(actionRequest, Collections.emptyMap()).isPresent());
   }
 
   public void testUnknownPropertyId() {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameters()).andReturn(new String[] {FIELD_ID, PROPERTY_ID});
-
-    replayMocks();
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameters()).thenReturn(new String[] {FIELD_ID, PROPERTY_ID});
 
     assertFalse(extractor.extract(actionRequest, Collections.emptyMap()).isPresent());
   }
 
   public void testHappyPath() {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameters()).andReturn(new String[] {PROPERTY_ID, FIELD_ID});
-
-    replayMocks();
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameters()).thenReturn(new String[] {PROPERTY_ID, FIELD_ID});
 
     Optional<AddPropertyToFieldParameters> extractedParameters =
         extractor.extract(actionRequest, Collections.singletonMap(PROPERTY_ID, PROPERTY_VALUE));
-    if (!extractedParameters.isPresent()) {
-      fail();
-    }
+    assertThat(extractedParameters).isPresent();
     assertEquals(PROPERTY_VALUE, extractedParameters.get().getPropertyValue());
     assertEquals(FIELD_ID, extractedParameters.get().getFieldId());
   }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddPropertyToFieldTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddPropertyToFieldTest.java
index a601b04..0f05875 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddPropertyToFieldTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddPropertyToFieldTest.java
@@ -14,20 +14,21 @@
 
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
-import static org.easymock.EasyMock.expect;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import com.google.gerrit.extensions.config.FactoryModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.googlesource.gerrit.plugins.its.base.its.ItsFacade;
-import com.googlesource.gerrit.plugins.its.base.testutil.MockingTestCase;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Optional;
-import org.easymock.EasyMock;
+import junit.framework.TestCase;
 
-public class AddPropertyToFieldTest extends MockingTestCase {
+public class AddPropertyToFieldTest extends TestCase {
 
   private static final String ISSUE_ID = "4711";
   private static final String FIELD_ID = "fieldId";
@@ -47,28 +48,25 @@
   private class TestModule extends FactoryModule {
     @Override
     protected void configure() {
-      parametersExtractor = createMock(AddPropertyToFieldParametersExtractor.class);
+      parametersExtractor = mock(AddPropertyToFieldParametersExtractor.class);
       bind(AddPropertyToFieldParametersExtractor.class).toInstance(parametersExtractor);
 
-      its = createMock(ItsFacade.class);
+      its = mock(ItsFacade.class);
       bind(ItsFacade.class).toInstance(its);
     }
   }
 
   public void testHappyPath() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
+    ActionRequest actionRequest = mock(ActionRequest.class);
 
     Map<String, String> properties = Collections.singletonMap(PROPERTY_ID, PROPERTY_VALUE);
-    expect(parametersExtractor.extract(actionRequest, properties))
-        .andReturn(Optional.of(new AddPropertyToFieldParameters(PROPERTY_VALUE, FIELD_ID)));
-
-    its.addValueToField(ISSUE_ID, PROPERTY_VALUE, FIELD_ID);
-    EasyMock.expectLastCall().once();
-
-    replayMocks();
+    when(parametersExtractor.extract(actionRequest, properties))
+        .thenReturn(Optional.of(new AddPropertyToFieldParameters(PROPERTY_VALUE, FIELD_ID)));
 
     AddPropertyToField addPropertyToField = createAddPropertyToField();
     addPropertyToField.execute(its, ISSUE_ID, actionRequest, properties);
+
+    verify(its).addValueToField(ISSUE_ID, PROPERTY_VALUE, FIELD_ID);
   }
 
   private AddPropertyToField createAddPropertyToField() {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddSoyCommentTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddSoyCommentTest.java
new file mode 100644
index 0000000..8b9e974
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddSoyCommentTest.java
@@ -0,0 +1,196 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.googlesource.gerrit.plugins.its.base.workflow;
+
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.ProvisionException;
+import com.googlesource.gerrit.plugins.its.base.ItsPath;
+import com.googlesource.gerrit.plugins.its.base.its.ItsFacade;
+import com.googlesource.gerrit.plugins.its.base.testutil.LoggingMockingTestCase;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map;
+import java.util.UUID;
+import org.eclipse.jgit.util.FileUtils;
+import org.junit.Test;
+
+public class AddSoyCommentTest extends LoggingMockingTestCase {
+  private Injector injector;
+
+  private ItsFacade its;
+  private boolean cleanupSitePath;
+  private Path itsPath;
+
+  @Test
+  public void testNoTemplateFileParameter() throws IOException {
+    ActionRequest actionRequest = new ActionRequest("foo");
+
+    AddSoyComment addSoyComment = createAddSoyComment();
+    addSoyComment.execute(its, "4711", actionRequest, ImmutableMap.of());
+
+    assertLogMessageContains("No template");
+  }
+
+  @Test
+  public void testTemplateFileDoesNotExist() {
+    ActionRequest actionRequest = new ActionRequest("foo nonExistingTemplate");
+
+    AddSoyComment addSoyComment = createAddSoyComment();
+
+    assertThrows(
+        ProvisionException.class,
+        () -> addSoyComment.execute(its, "4711", actionRequest, ImmutableMap.of()));
+  }
+
+  @Test
+  public void testPlain() throws IOException {
+    String templateName = "plain";
+
+    ActionRequest actionRequest = new ActionRequest("foo " + templateName);
+
+    injectTemplate(templateName, "bar");
+
+    AddSoyComment addSoyComment = createAddSoyComment();
+    addSoyComment.execute(its, "4711", actionRequest, ImmutableMap.of());
+
+    verify(its).addComment("4711", "bar");
+  }
+
+  @Test
+  public void testParameterPlain() throws IOException {
+    String templateName = "parameterPlain";
+
+    ActionRequest actionRequest = new ActionRequest("foo " + templateName);
+    Map<String, String> properties =
+        ImmutableMap.<String, String>builder().put("param1", "simple").build();
+
+    injectTemplate(templateName, "{@param param1:string}{$param1}");
+
+    AddSoyComment addSoyComment = createAddSoyComment();
+    addSoyComment.execute(its, "4711", actionRequest, properties);
+
+    verify(its).addComment("4711", "simple");
+  }
+
+  @Test
+  public void testParameterEscapingDefault() throws IOException {
+    String templateName = "parameterEscapingDefault";
+
+    ActionRequest actionRequest = new ActionRequest("foo " + templateName);
+    Map<String, String> properties =
+        ImmutableMap.<String, String>builder().put("param1", "<b>bar\"/>").build();
+
+    injectTemplate(templateName, "{@param param1:string}{$param1}");
+
+    AddSoyComment addSoyComment = createAddSoyComment();
+    addSoyComment.execute(its, "4711", actionRequest, properties);
+
+    verify(its).addComment("4711", "&lt;b&gt;bar&quot;/&gt;");
+  }
+
+  @Test
+  public void testParameterEscapingTextUnescaped() throws IOException {
+    String templateName = "parameterEscapingTextUnescaped";
+
+    ActionRequest actionRequest = new ActionRequest("foo " + templateName);
+    Map<String, String> properties =
+        ImmutableMap.<String, String>builder().put("param1", "<b>bar\"/>").build();
+
+    injectTemplate(templateName, "text", "{@param param1:string}{$param1}");
+
+    AddSoyComment addSoyComment = createAddSoyComment();
+    addSoyComment.execute(its, "4711", actionRequest, properties);
+
+    verify(its).addComment("4711", "<b>bar\"/>");
+  }
+
+  @Test
+  public void testParameterEscapingTextForcedEscapingUri() throws IOException {
+    String templateName = "parameterEscapingTextForcedEscapingUri";
+
+    ActionRequest actionRequest = new ActionRequest("foo " + templateName);
+    Map<String, String> properties =
+        ImmutableMap.<String, String>builder().put("param1", "<b>bar\"/>").build();
+
+    injectTemplate(templateName, "text", "{@param param1:string}{$param1|escapeUri}");
+
+    AddSoyComment addSoyComment = createAddSoyComment();
+    addSoyComment.execute(its, "4711", actionRequest, properties);
+
+    verify(its).addComment("4711", "%3Cb%3Ebar%22%2F%3E");
+  }
+
+  private AddSoyComment createAddSoyComment() {
+    return injector.getInstance(AddSoyComment.class);
+  }
+
+  @Override
+  public void setUp() throws Exception {
+    super.setUp();
+    cleanupSitePath = false;
+    injector = Guice.createInjector(new TestModule());
+  }
+
+  @Override
+  public void tearDown() throws Exception {
+    if (cleanupSitePath) {
+      if (Files.exists(itsPath)) {
+        FileUtils.delete(itsPath.toFile(), FileUtils.RECURSIVE);
+      }
+    }
+    super.tearDown();
+  }
+
+  private void injectTemplate(String name, String content) throws IOException {
+    injectTemplate(name, null, content);
+  }
+
+  private void injectTemplate(String name, String kind, String content) throws IOException {
+    Path templatePath = itsPath.resolve("templates").resolve(name + ".soy");
+    Files.createDirectories(templatePath.getParent());
+    String namespace = "{namespace etc.its.templates}";
+    String opening = "{template ." + name + (kind != null ? (" kind=\"" + kind + "\"") : "") + "}";
+    String closing = "{/template}";
+
+    String fullTemplate = namespace + opening + content + closing;
+
+    Files.write(templatePath, fullTemplate.getBytes());
+  }
+
+  private Path randomTargetPath() {
+    return Paths.get("target", "random_name_" + UUID.randomUUID().toString().replaceAll("-", "_"));
+  }
+
+  private class TestModule extends FactoryModule {
+    @Override
+    protected void configure() {
+      its = mock(ItsFacade.class);
+      bind(ItsFacade.class).toInstance(its);
+
+      itsPath = randomTargetPath().resolve("etc").resolve("its");
+      assertFalse("itsPath (" + itsPath + ") already exists", Files.exists(itsPath));
+      cleanupSitePath = true;
+      bind(Path.class).annotatedWith(ItsPath.class).toInstance(itsPath);
+    }
+  }
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddStandardCommentTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddStandardCommentTest.java
index d695bd1..ab11820 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddStandardCommentTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/AddStandardCommentTest.java
@@ -13,6 +13,9 @@
 // limitations under the License.
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
 import com.google.common.collect.ImmutableMap;
 import com.google.gerrit.extensions.config.FactoryModule;
 import com.google.inject.Guice;
@@ -28,19 +31,18 @@
   private ItsFacade its;
 
   public void testChangeMergedPlain() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
+    ActionRequest actionRequest = mock(ActionRequest.class);
 
     Map<String, String> properties = ImmutableMap.of("event-type", "change-merged");
 
-    its.addComment("42", "Change merged");
-    replayMocks();
-
     StandardAction action = injector.getInstance(AddStandardComment.class);
     action.execute(its, "42", actionRequest, properties);
+
+    verify(its).addComment("42", "Change merged");
   }
 
   public void testChangeMergedFull() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
+    ActionRequest actionRequest = mock(ActionRequest.class);
 
     Map<String, String> properties =
         ImmutableMap.<String, String>builder()
@@ -51,32 +53,31 @@
             .put("formatChangeUrl", "HtTp://ExAmPlE.OrG/ChAnGe")
             .build();
 
-    its.addComment(
-        "176",
-        "Change 4711 merged by John Doe:\n"
-            + "Test-Change-Subject\n"
-            + "\n"
-            + "HtTp://ExAmPlE.OrG/ChAnGe");
-    replayMocks();
-
     StandardAction action = injector.getInstance(AddStandardComment.class);
     action.execute(its, "176", actionRequest, properties);
+
+    verify(its)
+        .addComment(
+            "176",
+            "Change 4711 merged by John Doe:\n"
+                + "Test-Change-Subject\n"
+                + "\n"
+                + "HtTp://ExAmPlE.OrG/ChAnGe");
   }
 
   public void testChangeAbandonedPlain() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
+    ActionRequest actionRequest = mock(ActionRequest.class);
 
     Map<String, String> properties = ImmutableMap.of("event-type", "change-abandoned");
 
-    its.addComment("42", "Change abandoned");
-    replayMocks();
-
     StandardAction action = injector.getInstance(AddStandardComment.class);
     action.execute(its, "42", actionRequest, properties);
+
+    verify(its).addComment("42", "Change abandoned");
   }
 
   public void testChangeAbandonedFull() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
+    ActionRequest actionRequest = mock(ActionRequest.class);
 
     Map<String, String> properties =
         ImmutableMap.<String, String>builder()
@@ -88,35 +89,34 @@
             .put("formatChangeUrl", "HtTp://ExAmPlE.OrG/ChAnGe")
             .build();
 
-    its.addComment(
-        "176",
-        "Change 4711 abandoned by John Doe:\n"
-            + "Test-Change-Subject\n"
-            + "\n"
-            + "Reason:\n"
-            + "Test-Reason\n"
-            + "\n"
-            + "HtTp://ExAmPlE.OrG/ChAnGe");
-    replayMocks();
-
     StandardAction action = injector.getInstance(AddStandardComment.class);
     action.execute(its, "176", actionRequest, properties);
+
+    verify(its)
+        .addComment(
+            "176",
+            "Change 4711 abandoned by John Doe:\n"
+                + "Test-Change-Subject\n"
+                + "\n"
+                + "Reason:\n"
+                + "Test-Reason\n"
+                + "\n"
+                + "HtTp://ExAmPlE.OrG/ChAnGe");
   }
 
   public void testChangeRestoredPlain() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
+    ActionRequest actionRequest = mock(ActionRequest.class);
 
     Map<String, String> properties = ImmutableMap.of("event-type", "change-restored");
 
-    its.addComment("42", "Change restored");
-    replayMocks();
-
     StandardAction action = injector.getInstance(AddStandardComment.class);
     action.execute(its, "42", actionRequest, properties);
+
+    verify(its).addComment("42", "Change restored");
   }
 
   public void testChangeRestoredFull() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
+    ActionRequest actionRequest = mock(ActionRequest.class);
 
     Map<String, String> properties =
         ImmutableMap.<String, String>builder()
@@ -128,35 +128,34 @@
             .put("formatChangeUrl", "HtTp://ExAmPlE.OrG/ChAnGe")
             .build();
 
-    its.addComment(
-        "176",
-        "Change 4711 restored by John Doe:\n"
-            + "Test-Change-Subject\n"
-            + "\n"
-            + "Reason:\n"
-            + "Test-Reason\n"
-            + "\n"
-            + "HtTp://ExAmPlE.OrG/ChAnGe");
-    replayMocks();
-
     StandardAction action = injector.getInstance(AddStandardComment.class);
     action.execute(its, "176", actionRequest, properties);
+
+    verify(its)
+        .addComment(
+            "176",
+            "Change 4711 restored by John Doe:\n"
+                + "Test-Change-Subject\n"
+                + "\n"
+                + "Reason:\n"
+                + "Test-Reason\n"
+                + "\n"
+                + "HtTp://ExAmPlE.OrG/ChAnGe");
   }
 
   public void testPatchSetCreatedPlain() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
+    ActionRequest actionRequest = mock(ActionRequest.class);
 
     Map<String, String> properties = ImmutableMap.of("event-type", "patchset-created");
 
-    its.addComment("42", "Change had a related patch set uploaded");
-    replayMocks();
-
     StandardAction action = injector.getInstance(AddStandardComment.class);
     action.execute(its, "42", actionRequest, properties);
+
+    verify(its).addComment("42", "Change had a related patch set uploaded");
   }
 
   public void testPatchSetCreatedFull() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
+    ActionRequest actionRequest = mock(ActionRequest.class);
 
     Map<String, String> properties =
         ImmutableMap.<String, String>builder()
@@ -167,17 +166,17 @@
             .put("formatChangeUrl", "HtTp://ExAmPlE.OrG/ChAnGe")
             .build();
 
-    its.addComment(
-        "176",
-        "Change 4711 had a related patch set uploaded by "
-            + "John Doe:\n"
-            + "Test-Change-Subject\n"
-            + "\n"
-            + "HtTp://ExAmPlE.OrG/ChAnGe");
-    replayMocks();
-
     StandardAction action = injector.getInstance(AddStandardComment.class);
     action.execute(its, "176", actionRequest, properties);
+
+    verify(its)
+        .addComment(
+            "176",
+            "Change 4711 had a related patch set uploaded by "
+                + "John Doe:\n"
+                + "Test-Change-Subject\n"
+                + "\n"
+                + "HtTp://ExAmPlE.OrG/ChAnGe");
   }
 
   @Override
@@ -190,7 +189,7 @@
   private class TestModule extends FactoryModule {
     @Override
     protected void configure() {
-      its = createMock(ItsFacade.class);
+      its = mock(ItsFacade.class);
       bind(ItsFacade.class).toInstance(its);
     }
   }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ConditionTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ConditionTest.java
index 3df38cc..b31b3e2 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ConditionTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ConditionTest.java
@@ -33,8 +33,6 @@
 
     Map<String, String> properties = ImmutableMap.of("testKey", "testValue");
 
-    replayMocks();
-
     assertTrue("isMetBy gave false", condition.isMetBy(properties));
   }
 
@@ -43,8 +41,6 @@
 
     Map<String, String> properties = ImmutableMap.of();
 
-    replayMocks();
-
     assertFalse("isMetBy gave true", condition.isMetBy(properties));
   }
 
@@ -53,8 +49,6 @@
 
     Map<String, String> properties = ImmutableMap.of("otherKey", "testValue");
 
-    replayMocks();
-
     assertFalse("isMetBy gave true", condition.isMetBy(properties));
   }
 
@@ -63,8 +57,6 @@
 
     Map<String, String> properties = ImmutableMap.of("testKey", "otherValue");
 
-    replayMocks();
-
     assertFalse("isMetBy gave true", condition.isMetBy(properties));
   }
 
@@ -73,8 +65,6 @@
 
     Map<String, String> properties = ImmutableMap.of("testKey", "value2");
 
-    replayMocks();
-
     assertTrue("isMetBy gave false", condition.isMetBy(properties));
   }
 
@@ -83,8 +73,6 @@
 
     Map<String, String> properties = ImmutableMap.of("testKey", "value1 value3");
 
-    replayMocks();
-
     assertTrue("isMetBy gave false", condition.isMetBy(properties));
   }
 
@@ -93,8 +81,6 @@
 
     Map<String, String> properties = ImmutableMap.of("testKey", "value1 value3");
 
-    replayMocks();
-
     assertTrue("isMetBy gave false", condition.isMetBy(properties));
   }
 
@@ -103,8 +89,6 @@
 
     Map<String, String> properties = ImmutableMap.of("testKey", "value1 value2 value3");
 
-    replayMocks();
-
     assertTrue("isMetBy gave false", condition.isMetBy(properties));
   }
 
@@ -113,8 +97,6 @@
 
     Map<String, String> properties = ImmutableMap.of("testKey", "otherValue1 value2 otherValue3");
 
-    replayMocks();
-
     assertTrue("isMetBy gave false", condition.isMetBy(properties));
   }
 
@@ -123,8 +105,6 @@
 
     Map<String, String> properties = ImmutableMap.of();
 
-    replayMocks();
-
     assertTrue("isMetBy gave false", condition.isMetBy(properties));
   }
 
@@ -133,8 +113,6 @@
 
     Map<String, String> properties = ImmutableMap.of("otherKey", "testValue");
 
-    replayMocks();
-
     assertTrue("isMetBy gave false", condition.isMetBy(properties));
   }
 
@@ -143,8 +121,6 @@
 
     Map<String, String> properties = ImmutableMap.of("testKey", "otherValue");
 
-    replayMocks();
-
     assertTrue("isMetBy gave false", condition.isMetBy(properties));
   }
 
@@ -153,8 +129,6 @@
 
     Map<String, String> properties = ImmutableMap.of("testKey", "otherValue");
 
-    replayMocks();
-
     assertTrue("isMetBy gave false", condition.isMetBy(properties));
   }
 
@@ -163,8 +137,6 @@
 
     Map<String, String> properties = ImmutableMap.of("testKey", "value1");
 
-    replayMocks();
-
     assertFalse("isMetBy gave true", condition.isMetBy(properties));
   }
 
@@ -173,8 +145,6 @@
 
     Map<String, String> properties = ImmutableMap.of("testKey", "value1 value3");
 
-    replayMocks();
-
     assertFalse("isMetBy gave true", condition.isMetBy(properties));
   }
 
@@ -183,8 +153,6 @@
 
     Map<String, String> properties = ImmutableMap.of("testKey", "value1 value2 value3");
 
-    replayMocks();
-
     assertFalse("isMetBy gave true", condition.isMetBy(properties));
   }
 
@@ -192,7 +160,6 @@
     Condition condition = createCondition("testKey", "!,value1,value2,value3");
 
     Map<String, String> properties = ImmutableMap.of("testKey", "otherValue1 value2 otherValue3");
-    replayMocks();
 
     assertFalse("isMetBy gave true", condition.isMetBy(properties));
   }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/CreateVersionFromPropertyParametersExtractorTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/CreateVersionFromPropertyParametersExtractorTest.java
index 82b33e7..881fd6c 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/CreateVersionFromPropertyParametersExtractorTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/CreateVersionFromPropertyParametersExtractorTest.java
@@ -1,17 +1,18 @@
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
-import static org.easymock.EasyMock.expect;
+import static com.google.common.truth.Truth8.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import com.google.gerrit.extensions.config.FactoryModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
-import com.googlesource.gerrit.plugins.its.base.testutil.MockingTestCase;
 import java.util.Collections;
 import java.util.Optional;
+import junit.framework.TestCase;
 
-public class CreateVersionFromPropertyParametersExtractorTest extends MockingTestCase {
+public class CreateVersionFromPropertyParametersExtractorTest extends TestCase {
 
-  private static final String ITS_PROJECT = "test-project";
   private static final String PROPERTY_ID = "propertyId";
   private static final String PROPERTY_VALUE = "propertyValue";
 
@@ -35,10 +36,8 @@
   }
 
   private void testWrongNumberOfReceivedParameters(String[] parameters) {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameters()).andReturn(parameters);
-
-    replayMocks();
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameters()).thenReturn(parameters);
 
     Optional<CreateVersionFromPropertyParameters> extractedParameters =
         extractor.extract(actionRequest, Collections.emptyMap());
@@ -46,10 +45,8 @@
   }
 
   public void testBlankPropertyId() {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameters()).andReturn(new String[] {""});
-
-    replayMocks();
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameters()).thenReturn(new String[] {""});
 
     Optional<CreateVersionFromPropertyParameters> extractedParameters =
         extractor.extract(actionRequest, Collections.emptyMap());
@@ -57,10 +54,8 @@
   }
 
   public void testUnknownPropertyId() {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameters()).andReturn(new String[] {PROPERTY_ID});
-
-    replayMocks();
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameters()).thenReturn(new String[] {PROPERTY_ID});
 
     Optional<CreateVersionFromPropertyParameters> extractedParameters =
         extractor.extract(actionRequest, Collections.emptyMap());
@@ -68,16 +63,12 @@
   }
 
   public void testHappyPath() {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameters()).andReturn(new String[] {PROPERTY_ID});
-
-    replayMocks();
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameters()).thenReturn(new String[] {PROPERTY_ID});
 
     Optional<CreateVersionFromPropertyParameters> extractedParameters =
         extractor.extract(actionRequest, Collections.singletonMap(PROPERTY_ID, PROPERTY_VALUE));
-    if (!extractedParameters.isPresent()) {
-      fail();
-    }
+    assertThat(extractedParameters).isPresent();
     assertEquals(PROPERTY_VALUE, extractedParameters.get().getPropertyValue());
   }
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/CreateVersionFromPropertyTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/CreateVersionFromPropertyTest.java
index a89509c..7f3e2e0 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/CreateVersionFromPropertyTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/CreateVersionFromPropertyTest.java
@@ -14,23 +14,23 @@
 
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
-import static org.easymock.EasyMock.expect;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import com.google.gerrit.extensions.config.FactoryModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.googlesource.gerrit.plugins.its.base.its.ItsFacade;
-import com.googlesource.gerrit.plugins.its.base.testutil.MockingTestCase;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.Map;
 import java.util.Optional;
-import org.easymock.EasyMock;
+import junit.framework.TestCase;
 
-public class CreateVersionFromPropertyTest extends MockingTestCase {
+public class CreateVersionFromPropertyTest extends TestCase {
 
   private static final String ITS_PROJECT = "test-project";
-  private static final String PROPERTY_ID = "propertyId";
   private static final String PROPERTY_VALUE = "propertyValue";
 
   private Injector injector;
@@ -46,28 +46,25 @@
   private class TestModule extends FactoryModule {
     @Override
     protected void configure() {
-      its = createMock(ItsFacade.class);
+      its = mock(ItsFacade.class);
       bind(ItsFacade.class).toInstance(its);
 
-      parametersExtractor = createMock(CreateVersionFromPropertyParametersExtractor.class);
+      parametersExtractor = mock(CreateVersionFromPropertyParametersExtractor.class);
       bind(CreateVersionFromPropertyParametersExtractor.class).toInstance(parametersExtractor);
     }
   }
 
   public void testHappyPath() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
+    ActionRequest actionRequest = mock(ActionRequest.class);
 
     Map<String, String> properties = Collections.emptyMap();
-    expect(parametersExtractor.extract(actionRequest, properties))
-        .andReturn(Optional.of(new CreateVersionFromPropertyParameters(PROPERTY_VALUE)));
-
-    its.createVersion(ITS_PROJECT, PROPERTY_VALUE);
-    EasyMock.expectLastCall().once();
-
-    replayMocks();
+    when(parametersExtractor.extract(actionRequest, properties))
+        .thenReturn(Optional.of(new CreateVersionFromPropertyParameters(PROPERTY_VALUE)));
 
     CreateVersionFromProperty createVersionFromProperty = createCreateVersionFromProperty();
     createVersionFromProperty.execute(its, ITS_PROJECT, actionRequest, properties);
+
+    verify(its).createVersion(ITS_PROJECT, PROPERTY_VALUE);
   }
 
   private CreateVersionFromProperty createCreateVersionFromProperty() {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheTest.java
index 3b33b41..6b83097 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/ItsRulesProjectCacheTest.java
@@ -16,13 +16,14 @@
 
 import static com.googlesource.gerrit.plugins.its.base.workflow.RulesConfigReader.ACTION_KEY;
 import static com.googlesource.gerrit.plugins.its.base.workflow.RulesConfigReader.RULE_SECTION;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.isA;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.ImmutableList;
+import com.google.gerrit.entities.Project;
 import com.google.gerrit.extensions.config.FactoryModule;
-import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectLevelConfig;
 import com.google.gerrit.server.project.ProjectState;
@@ -41,10 +42,10 @@
   private class TestModule extends FactoryModule {
     @Override
     protected void configure() {
-      rulesConfigReader = createMock(RulesConfigReader.class);
+      rulesConfigReader = mock(RulesConfigReader.class);
       bind(RulesConfigReader.class).toInstance(rulesConfigReader);
 
-      projectCache = createMock(ProjectCache.class);
+      projectCache = mock(ProjectCache.class);
       bind(ProjectCache.class).toInstance(projectCache);
 
       bind(String.class)
@@ -79,22 +80,20 @@
     rule1.addActionRequest(action1);
     rule1.addCondition(condition1);
 
-    ProjectState projectState = createMock(ProjectState.class);
-    ProjectLevelConfig projectLevelConfigGlobal = createMock(ProjectLevelConfig.class);
+    ProjectState projectState = mock(ProjectState.class);
+    ProjectLevelConfig projectLevelConfigGlobal = mock(ProjectLevelConfig.class);
     Config projectGlobalCfg = new Config();
     projectGlobalCfg.setString(RULE_SECTION, RULE_1, CONDITION_KEY, VALUE_1);
     projectGlobalCfg.setString(RULE_SECTION, RULE_1, ACTION_KEY, ACTION_1);
-    expect(projectLevelConfigGlobal.get()).andReturn(projectGlobalCfg);
-    expect(projectState.getConfig(RuleBaseKind.GLOBAL.fileName))
-        .andReturn(projectLevelConfigGlobal);
-    ProjectLevelConfig projectLevelConfigPlugin = createMock(ProjectLevelConfig.class);
-    expect(projectLevelConfigPlugin.get()).andReturn(new Config());
-    expect(projectState.getConfig(RuleBaseKind.ITS.fileName)).andReturn(projectLevelConfigPlugin);
-    expect(projectCache.checkedGet(new Project.NameKey(TEST_PROJECT))).andReturn(projectState);
-    expect(rulesConfigReader.getRulesFromConfig(isA(Config.class)))
-        .andReturn(ImmutableList.of(rule1))
-        .andReturn(ImmutableList.of());
-    replayMocks();
+    when(projectLevelConfigGlobal.get()).thenReturn(projectGlobalCfg);
+    when(projectState.getConfig(RuleBaseKind.GLOBAL.fileName)).thenReturn(projectLevelConfigGlobal);
+    ProjectLevelConfig projectLevelConfigPlugin = mock(ProjectLevelConfig.class);
+    when(projectLevelConfigPlugin.get()).thenReturn(new Config());
+    when(projectState.getConfig(RuleBaseKind.ITS.fileName)).thenReturn(projectLevelConfigPlugin);
+    when(projectCache.checkedGet(Project.nameKey(TEST_PROJECT))).thenReturn(projectState);
+    when(rulesConfigReader.getRulesFromConfig(any(Config.class)))
+        .thenReturn(ImmutableList.of(rule1))
+        .thenReturn(ImmutableList.of());
 
     ItsRulesProjectCacheImpl.Loader loader =
         injector.getInstance(ItsRulesProjectCacheImpl.Loader.class);
@@ -112,37 +111,34 @@
     rule1.addActionRequest(action1);
     rule1.addCondition(condition1);
 
-    ProjectState projectState = createMock(ProjectState.class);
-    ProjectLevelConfig projectLevelConfigGlobal = createMock(ProjectLevelConfig.class);
-    expect(projectLevelConfigGlobal.get()).andReturn(new Config());
-    expect(projectState.getConfig(RuleBaseKind.GLOBAL.fileName))
-        .andReturn(projectLevelConfigGlobal);
-    ProjectLevelConfig projectLevelConfigPlugin = createMock(ProjectLevelConfig.class);
-    expect(projectLevelConfigPlugin.get()).andReturn(new Config());
-    expect(projectState.getConfig(RuleBaseKind.ITS.fileName)).andReturn(projectLevelConfigPlugin);
+    ProjectState projectState = mock(ProjectState.class);
+    ProjectLevelConfig projectLevelConfigGlobal = mock(ProjectLevelConfig.class);
+    when(projectLevelConfigGlobal.get()).thenReturn(new Config());
+    when(projectState.getConfig(RuleBaseKind.GLOBAL.fileName)).thenReturn(projectLevelConfigGlobal);
+    ProjectLevelConfig projectLevelConfigPlugin = mock(ProjectLevelConfig.class);
+    when(projectLevelConfigPlugin.get()).thenReturn(new Config());
+    when(projectState.getConfig(RuleBaseKind.ITS.fileName)).thenReturn(projectLevelConfigPlugin);
 
-    ProjectState parentProjectState = createMock(ProjectState.class);
-    ProjectLevelConfig parentProjectConfigGlobal = createMock(ProjectLevelConfig.class);
+    ProjectState parentProjectState = mock(ProjectState.class);
+    ProjectLevelConfig parentProjectConfigGlobal = mock(ProjectLevelConfig.class);
     Config parentGlobalCfg = new Config();
     parentGlobalCfg.setString(RULE_SECTION, RULE_1, CONDITION_KEY, VALUE_1);
     parentGlobalCfg.setString(RULE_SECTION, RULE_1, ACTION_KEY, ACTION_1);
-    expect(parentProjectConfigGlobal.get()).andReturn(parentGlobalCfg);
-    expect(parentProjectState.getConfig(RuleBaseKind.GLOBAL.fileName))
-        .andReturn(parentProjectConfigGlobal);
-    ProjectLevelConfig parentProjectConfigPlugin = createMock(ProjectLevelConfig.class);
-    expect(parentProjectConfigPlugin.get()).andReturn(new Config());
-    expect(parentProjectState.getConfig(RuleBaseKind.ITS.fileName))
-        .andReturn(parentProjectConfigPlugin);
-    expect(projectState.parents()).andReturn(FluentIterable.of(parentProjectState));
-    expect(projectCache.checkedGet(new Project.NameKey(TEST_PROJECT))).andReturn(projectState);
+    when(parentProjectConfigGlobal.get()).thenReturn(parentGlobalCfg);
+    when(parentProjectState.getConfig(RuleBaseKind.GLOBAL.fileName))
+        .thenReturn(parentProjectConfigGlobal);
+    ProjectLevelConfig parentProjectConfigPlugin = mock(ProjectLevelConfig.class);
+    when(parentProjectConfigPlugin.get()).thenReturn(new Config());
+    when(parentProjectState.getConfig(RuleBaseKind.ITS.fileName))
+        .thenReturn(parentProjectConfigPlugin);
+    when(projectState.parents()).thenReturn(FluentIterable.of(parentProjectState));
+    when(projectCache.checkedGet(Project.nameKey(TEST_PROJECT))).thenReturn(projectState);
 
-    expect(rulesConfigReader.getRulesFromConfig(isA(Config.class)))
-        .andReturn(ImmutableList.of())
-        .andReturn(ImmutableList.of())
-        .andReturn(ImmutableList.of(rule1))
-        .andReturn(ImmutableList.of());
-
-    replayMocks();
+    when(rulesConfigReader.getRulesFromConfig(any(Config.class)))
+        .thenReturn(ImmutableList.of())
+        .thenReturn(ImmutableList.of())
+        .thenReturn(ImmutableList.of(rule1))
+        .thenReturn(ImmutableList.of());
 
     ItsRulesProjectCacheImpl.Loader loader =
         injector.getInstance(ItsRulesProjectCacheImpl.Loader.class);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/LogEventTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/LogEventTest.java
index 0a26db8..5f82eae 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/LogEventTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/LogEventTest.java
@@ -13,7 +13,8 @@
 // limitations under the License.
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
-import static org.easymock.EasyMock.expect;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.gerrit.extensions.config.FactoryModule;
@@ -30,33 +31,27 @@
   private ItsFacade its;
 
   public void testNull() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn(null);
-
-    replayMocks();
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameter(1)).thenReturn(null);
 
     LogEvent logEvent = createLogEvent();
     logEvent.execute(null, "4711", actionRequest, ImmutableMap.of());
   }
 
   public void testEmpty() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("");
-
-    replayMocks();
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameter(1)).thenReturn("");
 
     LogEvent logEvent = createLogEvent();
     logEvent.execute(null, "4711", actionRequest, ImmutableMap.of());
   }
 
   public void testLevelDefault() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("");
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameter(1)).thenReturn("");
 
     Map<String, String> properties = ImmutableMap.of("KeyA", "ValueA");
 
-    replayMocks();
-
     LogEvent logEvent = createLogEvent();
     logEvent.execute(its, "4711", actionRequest, properties);
 
@@ -64,13 +59,11 @@
   }
 
   public void testLevelError() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("error");
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameter(1)).thenReturn("error");
 
     Map<String, String> properties = ImmutableMap.of("KeyA", "ValueA");
 
-    replayMocks();
-
     LogEvent logEvent = createLogEvent();
     logEvent.execute(its, "4711", actionRequest, properties);
 
@@ -78,13 +71,11 @@
   }
 
   public void testLevelWarn() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("warn");
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameter(1)).thenReturn("warn");
 
     Map<String, String> properties = ImmutableMap.of("KeyA", "ValueA");
 
-    replayMocks();
-
     LogEvent logEvent = createLogEvent();
     logEvent.execute(its, "4711", actionRequest, properties);
 
@@ -92,13 +83,11 @@
   }
 
   public void testLevelInfo() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("info");
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameter(1)).thenReturn("info");
 
     Map<String, String> properties = ImmutableMap.of("KeyA", "ValueA");
 
-    replayMocks();
-
     LogEvent logEvent = createLogEvent();
     logEvent.execute(its, "4711", actionRequest, properties);
 
@@ -106,13 +95,11 @@
   }
 
   public void testLevelDebug() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("debug");
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameter(1)).thenReturn("debug");
 
     Map<String, String> properties = ImmutableMap.of("KeyA", "ValueA");
 
-    replayMocks();
-
     LogEvent logEvent = createLogEvent();
     logEvent.execute(its, "4711", actionRequest, properties);
 
@@ -120,8 +107,8 @@
   }
 
   public void testMultipleProperties() throws IOException {
-    ActionRequest actionRequest = createMock(ActionRequest.class);
-    expect(actionRequest.getParameter(1)).andReturn("info");
+    ActionRequest actionRequest = mock(ActionRequest.class);
+    when(actionRequest.getParameter(1)).thenReturn("info");
 
     Map<String, String> properties =
         ImmutableMap.<String, String>builder()
@@ -130,8 +117,6 @@
             .put("KeyC", "ValueC")
             .build();
 
-    replayMocks();
-
     LogEvent logEvent = createLogEvent();
     logEvent.execute(its, "4711", actionRequest, properties);
 
@@ -153,7 +138,7 @@
   private class TestModule extends FactoryModule {
     @Override
     protected void configure() {
-      its = createMock(ItsFacade.class);
+      its = mock(ItsFacade.class);
     }
   }
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/RuleBaseTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/RuleBaseTest.java
index 305e8d1..717886c 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/RuleBaseTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/RuleBaseTest.java
@@ -14,8 +14,9 @@
 
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.isA;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -66,22 +67,20 @@
     String rules = "[rule \"rule1\"]\n\taction = action1\n";
     injectRuleBase(rules);
 
-    Rule rule1 = createMock(Rule.class);
-    ActionRequest actionRequest1 = createMock(ActionRequest.class);
+    Rule rule1 = mock(Rule.class);
+    ActionRequest actionRequest1 = mock(ActionRequest.class);
 
     Map<String, String> properties = ImmutableMap.of(PROJECT_KEY, TEST_PROJECT);
 
     List<ActionRequest> rule1Match = Lists.newArrayListWithCapacity(1);
     rule1Match.add(actionRequest1);
-    expect(rule1.actionRequestsFor(properties)).andReturn(rule1Match);
+    when(rule1.actionRequestsFor(properties)).thenReturn(rule1Match);
 
-    expect(rulesConfigReader.getRulesFromConfig(isA(Config.class)))
-        .andReturn(ImmutableList.of(rule1))
-        .once();
+    when(rulesConfigReader.getRulesFromConfig(any(Config.class)))
+        .thenReturn(ImmutableList.of(rule1))
+        .thenThrow(new UnsupportedOperationException("Method called more than once"));
 
-    expect(rulesProjectCache.get(TEST_PROJECT)).andReturn(ImmutableList.of());
-
-    replayMocks();
+    when(rulesProjectCache.get(TEST_PROJECT)).thenReturn(ImmutableList.of());
 
     RuleBase ruleBase = createRuleBase();
     Collection<ActionRequest> actual = ruleBase.actionRequestsFor(properties);
@@ -101,29 +100,26 @@
             + "[rule \"rule2\"]\n"
             + "\taction = action3\n");
 
-    Rule rule1 = createMock(Rule.class);
-    ActionRequest actionRequest1 = createMock(ActionRequest.class);
-    ActionRequest actionRequest2 = createMock(ActionRequest.class);
+    Rule rule1 = mock(Rule.class);
+    ActionRequest actionRequest1 = mock(ActionRequest.class);
+    ActionRequest actionRequest2 = mock(ActionRequest.class);
 
-    Rule rule2 = createMock(Rule.class);
-    ActionRequest actionRequest3 = createMock(ActionRequest.class);
+    Rule rule2 = mock(Rule.class);
+    ActionRequest actionRequest3 = mock(ActionRequest.class);
 
     Map<String, String> properties = ImmutableMap.of(PROJECT_KEY, TEST_PROJECT);
 
     List<ActionRequest> rule1Match = ImmutableList.of(actionRequest1, actionRequest2);
-    expect(rule1.actionRequestsFor(properties)).andReturn(rule1Match).anyTimes();
+    when(rule1.actionRequestsFor(properties)).thenReturn(rule1Match);
 
     List<ActionRequest> rule2Match = ImmutableList.of(actionRequest3);
-    expect(rule2.actionRequestsFor(properties)).andReturn(rule2Match).anyTimes();
+    when(rule2.actionRequestsFor(properties)).thenReturn(rule2Match);
 
-    expect(rulesProjectCache.get(TEST_PROJECT)).andReturn(ImmutableList.of());
+    when(rulesProjectCache.get(TEST_PROJECT)).thenReturn(ImmutableList.of());
 
-    expect(rulesConfigReader.getRulesFromConfig(isA(Config.class)))
-        .andReturn(ImmutableList.of(rule1, rule2))
-        .andReturn(ImmutableList.of())
-        .anyTimes();
-
-    replayMocks();
+    when(rulesConfigReader.getRulesFromConfig(any(Config.class)))
+        .thenReturn(ImmutableList.of(rule1, rule2))
+        .thenReturn(ImmutableList.of());
 
     RuleBase ruleBase = createRuleBase();
     Collection<ActionRequest> actual = ruleBase.actionRequestsFor(properties);
@@ -140,26 +136,23 @@
 
     Map<String, String> properties = ImmutableMap.of(PROJECT_KEY, TEST_PROJECT);
 
-    Rule rule2 = createMock(Rule.class);
-    ActionRequest actionRequest2 = createMock(ActionRequest.class);
+    Rule rule2 = mock(Rule.class);
+    ActionRequest actionRequest2 = mock(ActionRequest.class);
 
     List<ActionRequest> rule2Match = ImmutableList.of(actionRequest2);
-    expect(rule2.actionRequestsFor(properties)).andReturn(rule2Match);
+    when(rule2.actionRequestsFor(properties)).thenReturn(rule2Match);
 
-    Rule rule3 = createMock(Rule.class);
-    ActionRequest actionRequest3 = createMock(ActionRequest.class);
+    Rule rule3 = mock(Rule.class);
+    ActionRequest actionRequest3 = mock(ActionRequest.class);
 
     List<ActionRequest> rule3Match = ImmutableList.of(actionRequest3);
-    expect(rule3.actionRequestsFor(properties)).andReturn(rule3Match);
+    when(rule3.actionRequestsFor(properties)).thenReturn(rule3Match);
 
-    expect(rulesProjectCache.get(TEST_PROJECT)).andReturn(ImmutableList.of());
+    when(rulesProjectCache.get(TEST_PROJECT)).thenReturn(ImmutableList.of());
 
-    expect(rulesConfigReader.getRulesFromConfig(isA(Config.class)))
-        .andReturn(ImmutableList.of(rule2, rule3))
-        .andReturn(ImmutableList.of())
-        .anyTimes();
-
-    replayMocks();
+    when(rulesConfigReader.getRulesFromConfig(any(Config.class)))
+        .thenReturn(ImmutableList.of(rule2, rule3))
+        .thenReturn(ImmutableList.of());
 
     RuleBase ruleBase = createRuleBase();
 
@@ -171,17 +164,15 @@
   }
 
   public void testProjectConfigIsLoaded() {
-    Rule rule1 = createMock(Rule.class);
-    ActionRequest actionRequest1 = createMock(ActionRequest.class);
+    Rule rule1 = mock(Rule.class);
+    ActionRequest actionRequest1 = mock(ActionRequest.class);
 
     Map<String, String> properties = ImmutableMap.of(PROJECT_KEY, TEST_PROJECT);
 
     List<ActionRequest> rule1Match = ImmutableList.of(actionRequest1);
-    expect(rule1.actionRequestsFor(properties)).andReturn(rule1Match);
+    when(rule1.actionRequestsFor(properties)).thenReturn(rule1Match);
 
-    expect(rulesProjectCache.get(TEST_PROJECT)).andReturn(ImmutableList.of(rule1));
-
-    replayMocks();
+    when(rulesProjectCache.get(TEST_PROJECT)).thenReturn(ImmutableList.of(rule1));
 
     RuleBase ruleBase = createRuleBase();
     Collection<ActionRequest> actual = ruleBase.actionRequestsFor(properties);
@@ -238,10 +229,10 @@
 
       bind(Path.class).annotatedWith(ItsPath.class).toInstance(itsPath);
 
-      rulesConfigReader = createMock(RulesConfigReader.class);
+      rulesConfigReader = mock(RulesConfigReader.class);
       bind(RulesConfigReader.class).toInstance(rulesConfigReader);
 
-      rulesProjectCache = createMock(ItsRulesProjectCache.class);
+      rulesProjectCache = mock(ItsRulesProjectCache.class);
       bind(ItsRulesProjectCache.class).toInstance(rulesProjectCache);
 
       bind(String.class)
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/RuleTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/RuleTest.java
index c106a81..91f5072 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/RuleTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/RuleTest.java
@@ -13,7 +13,8 @@
 // limitations under the License.
 package com.googlesource.gerrit.plugins.its.base.workflow;
 
-import static org.easymock.EasyMock.expect;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
@@ -39,11 +40,9 @@
 
     Rule rule = createRule("testRule");
 
-    ActionRequest actionRequest1 = createMock(ActionRequest.class);
+    ActionRequest actionRequest1 = mock(ActionRequest.class);
     rule.addActionRequest(actionRequest1);
 
-    replayMocks();
-
     Collection<ActionRequest> actual = rule.actionRequestsFor(properties);
 
     Collection<ActionRequest> expected = Lists.newArrayListWithCapacity(1);
@@ -56,15 +55,13 @@
 
     Rule rule = createRule("testRule");
 
-    Condition condition1 = createMock(Condition.class);
-    expect(condition1.isMetBy(properties)).andReturn(false).anyTimes();
+    Condition condition1 = mock(Condition.class);
+    when(condition1.isMetBy(properties)).thenReturn(false);
     rule.addCondition(condition1);
 
-    ActionRequest actionRequest1 = createMock(ActionRequest.class);
+    ActionRequest actionRequest1 = mock(ActionRequest.class);
     rule.addActionRequest(actionRequest1);
 
-    replayMocks();
-
     Collection<ActionRequest> actual = rule.actionRequestsFor(properties);
 
     List<ActionRequest> expected = Collections.emptyList();
@@ -76,19 +73,17 @@
 
     Rule rule = createRule("testRule");
 
-    Condition condition1 = createMock(Condition.class);
-    expect(condition1.isMetBy(properties)).andReturn(true).anyTimes();
+    Condition condition1 = mock(Condition.class);
+    when(condition1.isMetBy(properties)).thenReturn(true);
     rule.addCondition(condition1);
 
-    Condition condition2 = createMock(Condition.class);
-    expect(condition2.isMetBy(properties)).andReturn(false).anyTimes();
+    Condition condition2 = mock(Condition.class);
+    when(condition2.isMetBy(properties)).thenReturn(false);
     rule.addCondition(condition2);
 
-    ActionRequest actionRequest1 = createMock(ActionRequest.class);
+    ActionRequest actionRequest1 = mock(ActionRequest.class);
     rule.addActionRequest(actionRequest1);
 
-    replayMocks();
-
     Collection<ActionRequest> actual = rule.actionRequestsFor(properties);
 
     List<ActionRequest> expected = Collections.emptyList();
@@ -100,14 +95,12 @@
 
     Rule rule = createRule("testRule");
 
-    ActionRequest actionRequest1 = createMock(ActionRequest.class);
+    ActionRequest actionRequest1 = mock(ActionRequest.class);
     rule.addActionRequest(actionRequest1);
 
-    ActionRequest actionRequest2 = createMock(ActionRequest.class);
+    ActionRequest actionRequest2 = mock(ActionRequest.class);
     rule.addActionRequest(actionRequest2);
 
-    replayMocks();
-
     Collection<ActionRequest> actual = rule.actionRequestsFor(properties);
 
     List<ActionRequest> expected = Lists.newArrayListWithCapacity(1);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/RulesConfigReaderTest.java b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/RulesConfigReaderTest.java
index 96fb869..12535f2 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/RulesConfigReaderTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/its/base/workflow/RulesConfigReaderTest.java
@@ -16,7 +16,9 @@
 
 import static com.googlesource.gerrit.plugins.its.base.workflow.RulesConfigReader.ACTION_KEY;
 import static com.googlesource.gerrit.plugins.its.base.workflow.RulesConfigReader.RULE_SECTION;
-import static org.easymock.EasyMock.expect;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import com.google.common.collect.ImmutableList;
 import com.google.gerrit.extensions.config.FactoryModule;
@@ -31,13 +33,13 @@
   private class TestModule extends FactoryModule {
     @Override
     protected void configure() {
-      ruleFactory = createMock(Rule.Factory.class);
+      ruleFactory = mock(Rule.Factory.class);
       bind(Rule.Factory.class).toInstance(ruleFactory);
 
-      conditionFactory = createMock(Condition.Factory.class);
+      conditionFactory = mock(Condition.Factory.class);
       bind(Condition.Factory.class).toInstance(conditionFactory);
 
-      actionRequestFactory = createMock(ActionRequest.Factory.class);
+      actionRequestFactory = mock(ActionRequest.Factory.class);
       bind(ActionRequest.Factory.class).toInstance(actionRequestFactory);
     }
   }
@@ -63,22 +65,21 @@
     cfg.setString(RULE_SECTION, RULE_1, CONDITION_KEY, VALUE_1);
     cfg.setString(RULE_SECTION, RULE_1, ACTION_KEY, ACTION_1);
 
-    Rule rule1 = createMock(Rule.class);
-    expect(ruleFactory.create(RULE_1)).andReturn(rule1);
+    Rule rule1 = mock(Rule.class);
+    when(ruleFactory.create(RULE_1)).thenReturn(rule1);
 
-    ActionRequest actionRequest1 = createMock(ActionRequest.class);
-    expect(actionRequestFactory.create(ACTION_1)).andReturn(actionRequest1);
-    rule1.addActionRequest(actionRequest1);
+    ActionRequest actionRequest1 = mock(ActionRequest.class);
+    when(actionRequestFactory.create(ACTION_1)).thenReturn(actionRequest1);
 
-    Condition condition1 = createMock(Condition.class);
-    expect(conditionFactory.create(CONDITION_KEY, VALUE_1)).andReturn(condition1);
-    rule1.addCondition(condition1);
-
-    replayMocks();
+    Condition condition1 = mock(Condition.class);
+    when(conditionFactory.create(CONDITION_KEY, VALUE_1)).thenReturn(condition1);
 
     Collection<Rule> expected = ImmutableList.of(rule1);
 
     RulesConfigReader rulesConfigReader = injector.getInstance(RulesConfigReader.class);
     assertEquals("Rules do not match", expected, rulesConfigReader.getRulesFromConfig(cfg));
+
+    verify(rule1).addActionRequest(actionRequest1);
+    verify(rule1).addCondition(condition1);
   }
 }
diff --git a/tools/bzl/classpath.bzl b/tools/bzl/classpath.bzl
index d5764f7..c921d01 100644
--- a/tools/bzl/classpath.bzl
+++ b/tools/bzl/classpath.bzl
@@ -1,4 +1,6 @@
 load(
     "@com_googlesource_gerrit_bazlets//tools:classpath.bzl",
-    "classpath_collector",
+    _classpath_collector = "classpath_collector",
 )
+
+classpath_collector = _classpath_collector
diff --git a/tools/bzl/junit.bzl b/tools/bzl/junit.bzl
index 3af7e58..97307bd 100644
--- a/tools/bzl/junit.bzl
+++ b/tools/bzl/junit.bzl
@@ -1,4 +1,6 @@
 load(
     "@com_googlesource_gerrit_bazlets//tools:junit.bzl",
-    "junit_tests",
+    _junit_tests = "junit_tests",
 )
+
+junit_tests = _junit_tests
diff --git a/tools/bzl/maven_jar.bzl b/tools/bzl/maven_jar.bzl
deleted file mode 100644
index 2eabedb..0000000
--- a/tools/bzl/maven_jar.bzl
+++ /dev/null
@@ -1 +0,0 @@
-load("@com_googlesource_gerrit_bazlets//tools:maven_jar.bzl", "maven_jar")
diff --git a/tools/bzl/plugin.bzl b/tools/bzl/plugin.bzl
index 0b25d23..4d2dbdd 100644
--- a/tools/bzl/plugin.bzl
+++ b/tools/bzl/plugin.bzl
@@ -1,6 +1,10 @@
 load(
     "@com_googlesource_gerrit_bazlets//:gerrit_plugin.bzl",
-    "PLUGIN_DEPS",
-    "PLUGIN_TEST_DEPS",
-    "gerrit_plugin",
+    _gerrit_plugin = "gerrit_plugin",
+    _plugin_deps = "PLUGIN_DEPS",
+    _plugin_test_deps = "PLUGIN_TEST_DEPS",
 )
+
+gerrit_plugin = _gerrit_plugin
+PLUGIN_DEPS = _plugin_deps
+PLUGIN_TEST_DEPS = _plugin_test_deps