From 6d6ba014c967c48ac7e9348556677de2a27a7965 Mon Sep 17 00:00:00 2001
From: Tim te Beek <timtebeek@gmail.com>
Date: Wed, 13 Dec 2023 10:16:19 +0100
Subject: [PATCH] refactor: AssertJ best practices (#3637)

Use this link to re-run the recipe: https://app.moderne.io/recipes/org.openrewrite.java.testing.assertj.Assertj

Co-authored-by: Moderne <team@moderne.io>
---
 .../activemq/ITActiveMQCollector.java         |  4 +-
 .../collector/CollectorSamplerTest.java       |  5 +--
 ...ipkinScribeCollectorConfigurationTest.java |  4 +-
 .../internal/ZipkinHttpConfigurationTest.java |  4 +-
 ...kinActiveMQCollectorConfigurationTest.java |  4 +-
 ...ElasticsearchStorageConfigurationTest.java | 38 +++++++++----------
 ...ZipkinKafkaCollectorConfigurationTest.java |  8 ++--
 ...kinRabbitMQCollectorConfigurationTest.java | 12 +++---
 .../ThrottledStorageComponentTest.java        |  4 +-
 .../ui/ZipkinUiConfigurationTest.java         | 10 ++---
 .../ZipkinMySQLStorageConfigurationTest.java  |  4 +-
 .../elasticsearch/JsonReadersTest.java        |  4 +-
 .../src/test/java/zipkin2/AnnotationTest.java |  3 +-
 .../src/test/java/zipkin2/CallTest.java       |  4 +-
 .../src/test/java/zipkin2/EndpointTest.java   |  5 +--
 .../zipkin2/SpanBytesDecoderDetectorTest.java | 28 +++++++-------
 .../src/test/java/zipkin2/SpanTest.java       | 20 +++++-----
 .../zipkin2/codec/SpanBytesDecoderTest.java   | 28 ++++++--------
 .../zipkin2/codec/V1SpanBytesDecoderTest.java | 26 +++++--------
 .../zipkin2/internal/AggregateCallTest.java   |  4 +-
 .../java/zipkin2/internal/JsonCodecTest.java  |  9 +----
 .../java/zipkin2/internal/SpanNodeTest.java   |  6 +--
 .../zipkin2/storage/QueryRequestTest.java     | 13 +++----
 23 files changed, 111 insertions(+), 136 deletions(-)

diff --git a/zipkin-collector/activemq/src/test/java/zipkin2/collector/activemq/ITActiveMQCollector.java b/zipkin-collector/activemq/src/test/java/zipkin2/collector/activemq/ITActiveMQCollector.java
index a446fd7dae8..dcdff8df6cc 100644
--- a/zipkin-collector/activemq/src/test/java/zipkin2/collector/activemq/ITActiveMQCollector.java
+++ b/zipkin-collector/activemq/src/test/java/zipkin2/collector/activemq/ITActiveMQCollector.java
@@ -41,7 +41,6 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 import static zipkin2.TestObjects.LOTS_OF_SPANS;
 import static zipkin2.TestObjects.UTF_8;
 import static zipkin2.codec.SpanBytesEncoder.PROTO3;
@@ -97,8 +96,7 @@ public class ITActiveMQCollector {
       collector = builder().connectionFactory(connectionFactory).build();
       collector.start();
     });
-    assertTrue(exception.getMessage()
-      .contains("Unable to establish connection to ActiveMQ broker: Connection refused"));
+    assertThat(exception.getMessage()).contains("Unable to establish connection to ActiveMQ broker: Connection refused");
   }
 
   /**
diff --git a/zipkin-collector/core/src/test/java/zipkin2/collector/CollectorSamplerTest.java b/zipkin-collector/core/src/test/java/zipkin2/collector/CollectorSamplerTest.java
index eda661ecd60..ad6f8b757c1 100644
--- a/zipkin-collector/core/src/test/java/zipkin2/collector/CollectorSamplerTest.java
+++ b/zipkin-collector/core/src/test/java/zipkin2/collector/CollectorSamplerTest.java
@@ -20,7 +20,6 @@
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.data.Percentage.withPercentage;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 import static zipkin2.TestObjects.LOTS_OF_SPANS;
 
 public class CollectorSamplerTest {
@@ -77,12 +76,12 @@ public class CollectorSamplerTest {
 
   @Test void rateCantBeNegative() {
     Throwable exception = assertThrows(IllegalArgumentException.class, () -> CollectorSampler.create(-1.0f));
-    assertTrue(exception.getMessage().contains("rate should be between 0 and 1: was -1.0"));
+    assertThat(exception.getMessage()).contains("rate should be between 0 and 1: was -1.0");
   }
 
   @Test void rateCantBeOverOne() {
     Throwable exception = assertThrows(IllegalArgumentException.class, () -> CollectorSampler.create(1.1f));
-    assertTrue(exception.getMessage().contains("rate should be between 0 and 1: was 1.1"));
+    assertThat(exception.getMessage()).contains("rate should be between 0 and 1: was 1.1");
   }
 
   static Stream<Span> lotsOfSpans() {
diff --git a/zipkin-server/src/test/java/zipkin2/collector/scribe/ZipkinScribeCollectorConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/collector/scribe/ZipkinScribeCollectorConfigurationTest.java
index 97853c29f68..a13c0baf72f 100644
--- a/zipkin-server/src/test/java/zipkin2/collector/scribe/ZipkinScribeCollectorConfigurationTest.java
+++ b/zipkin-server/src/test/java/zipkin2/collector/scribe/ZipkinScribeCollectorConfigurationTest.java
@@ -23,7 +23,7 @@
 import zipkin2.server.internal.scribe.ZipkinScribeCollectorConfiguration;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 
 public class ZipkinScribeCollectorConfigurationTest {
   AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@@ -33,7 +33,7 @@ public class ZipkinScribeCollectorConfigurationTest {
   }
 
   @Test void doesntProvidesCollectorComponent_byDefault() {
-    assertThrows(NoSuchBeanDefinitionException.class, () -> {
+    assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
       refreshContext();
 
       context.getBean(ScribeCollector.class);
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/ZipkinHttpConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/server/internal/ZipkinHttpConfigurationTest.java
index d6392f8c38f..7d1d40a8257 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/ZipkinHttpConfigurationTest.java
+++ b/zipkin-server/src/test/java/zipkin2/server/internal/ZipkinHttpConfigurationTest.java
@@ -32,7 +32,7 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 
 public class ZipkinHttpConfigurationTest {
   AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@@ -50,7 +50,7 @@ public class ZipkinHttpConfigurationTest {
   }
 
   @Test void httpCollector_canDisable() {
-    assertThrows(NoSuchBeanDefinitionException.class, () -> {
+    assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
       TestPropertyValues.of("zipkin.collector.http.enabled:false").applyTo(context);
       registerBaseConfig(context);
       context.register(ZipkinHttpCollector.class);
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/activemq/ZipkinActiveMQCollectorConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/server/internal/activemq/ZipkinActiveMQCollectorConfigurationTest.java
index ea7fb9ebb14..78b804755e8 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/activemq/ZipkinActiveMQCollectorConfigurationTest.java
+++ b/zipkin-server/src/test/java/zipkin2/server/internal/activemq/ZipkinActiveMQCollectorConfigurationTest.java
@@ -25,7 +25,7 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 
 public class ZipkinActiveMQCollectorConfigurationTest {
 
@@ -36,7 +36,7 @@ public class ZipkinActiveMQCollectorConfigurationTest {
   }
 
   @Test void doesNotProvideCollectorComponent_whenAddressAndUriNotSet() {
-    assertThrows(NoSuchBeanDefinitionException.class, () -> {
+    assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
       context.register(
         PropertyPlaceholderAutoConfiguration.class,
         ZipkinActiveMQCollectorConfiguration.class,
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/elasticsearch/ZipkinElasticsearchStorageConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/server/internal/elasticsearch/ZipkinElasticsearchStorageConfigurationTest.java
index 4cb91524497..30ac203bf8d 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/elasticsearch/ZipkinElasticsearchStorageConfigurationTest.java
+++ b/zipkin-server/src/test/java/zipkin2/server/internal/elasticsearch/ZipkinElasticsearchStorageConfigurationTest.java
@@ -34,7 +34,7 @@
 import zipkin2.elasticsearch.ElasticsearchStorage;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 import static zipkin2.server.internal.elasticsearch.ITElasticsearchDynamicCredentials.pathOfResource;
 
 public class ZipkinElasticsearchStorageConfigurationTest {
@@ -45,7 +45,7 @@ public class ZipkinElasticsearchStorageConfigurationTest {
   }
 
   @Test void doesntProvideStorageComponent_whenStorageTypeNotElasticsearch() {
-    assertThrows(NoSuchBeanDefinitionException.class, () -> {
+    assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
       TestPropertyValues.of("zipkin.storage.type:cassandra").applyTo(context);
       Access.registerElasticsearch(context);
       context.refresh();
@@ -256,11 +256,11 @@ static class CustomizerConfiguration {
   }
 
   @Test void dailyIndexFormat_overridingDateSeparator_invalidToBeMultiChar() {
-    assertThrows(BeanCreationException.class, () -> {
+    assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() -> {
       TestPropertyValues.of(
-          "zipkin.storage.type:elasticsearch",
-          "zipkin.storage.elasticsearch.hosts:http://host1:9200",
-          "zipkin.storage.elasticsearch.date-separator:blagho")
+        "zipkin.storage.type:elasticsearch",
+        "zipkin.storage.elasticsearch.hosts:http://host1:9200",
+        "zipkin.storage.elasticsearch.date-separator:blagho")
         .applyTo(context);
       Access.registerElasticsearch(context);
 
@@ -337,13 +337,13 @@ static class CustomizerConfiguration {
   }
 
   @Test void providesBasicAuthInterceptor_whenInvalidDynamicCredentialsConfigured() {
-    assertThrows(BeanCreationException.class, () -> {
+    assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() -> {
       String credentialsFile = pathOfResource("es-credentials-invalid");
       TestPropertyValues.of(
-          "zipkin.storage.type:elasticsearch",
-          "zipkin.storage.elasticsearch.hosts:127.0.0.1:1234",
-          "zipkin.storage.elasticsearch.credentials-file:" + credentialsFile,
-          "zipkin.storage.elasticsearch.credentials-refresh-interval:2")
+        "zipkin.storage.type:elasticsearch",
+        "zipkin.storage.elasticsearch.hosts:127.0.0.1:1234",
+        "zipkin.storage.elasticsearch.credentials-file:" + credentialsFile,
+        "zipkin.storage.elasticsearch.credentials-refresh-interval:2")
         .applyTo(context);
       Access.registerElasticsearch(context);
       context.refresh();
@@ -351,12 +351,12 @@ static class CustomizerConfiguration {
   }
 
   @Test void providesBasicAuthInterceptor_whenDynamicCredentialsConfiguredButFileAbsent() {
-    assertThrows(BeanCreationException.class, () -> {
+    assertThatExceptionOfType(BeanCreationException.class).isThrownBy(() -> {
       TestPropertyValues.of(
-          "zipkin.storage.type:elasticsearch",
-          "zipkin.storage.elasticsearch.hosts:127.0.0.1:1234",
-          "zipkin.storage.elasticsearch.credentials-file:no-this-file",
-          "zipkin.storage.elasticsearch.credentials-refresh-interval:2")
+        "zipkin.storage.type:elasticsearch",
+        "zipkin.storage.elasticsearch.hosts:127.0.0.1:1234",
+        "zipkin.storage.elasticsearch.credentials-file:no-this-file",
+        "zipkin.storage.elasticsearch.credentials-refresh-interval:2")
         .applyTo(context);
       Access.registerElasticsearch(context);
       context.refresh();
@@ -436,10 +436,10 @@ static class CustomizerConfiguration {
   }
 
   @Test void templatePriority_Invalid() {
-    assertThrows(UnsatisfiedDependencyException.class, () -> {
+    assertThatExceptionOfType(UnsatisfiedDependencyException.class).isThrownBy(() -> {
       TestPropertyValues.of(
-          "zipkin.storage.type:elasticsearch",
-          "zipkin.storage.elasticsearch.template-priority:string")
+        "zipkin.storage.type:elasticsearch",
+        "zipkin.storage.elasticsearch.template-priority:string")
         .applyTo(context);
       Access.registerElasticsearch(context);
       context.refresh();
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/kafka/ZipkinKafkaCollectorConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/server/internal/kafka/ZipkinKafkaCollectorConfigurationTest.java
index 73dbaf9f56b..5fa3ab13931 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/kafka/ZipkinKafkaCollectorConfigurationTest.java
+++ b/zipkin-server/src/test/java/zipkin2/server/internal/kafka/ZipkinKafkaCollectorConfigurationTest.java
@@ -23,7 +23,7 @@
 import zipkin2.server.internal.InMemoryConfiguration;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 
 public class ZipkinKafkaCollectorConfigurationTest {
 
@@ -34,7 +34,7 @@ public class ZipkinKafkaCollectorConfigurationTest {
   }
 
   @Test void doesNotProvideCollectorComponent_whenBootstrapServersUnset() {
-    assertThrows(NoSuchBeanDefinitionException.class, () -> {
+    assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
       context.register(
         PropertyPlaceholderAutoConfiguration.class,
         ZipkinKafkaCollectorConfiguration.class,
@@ -45,7 +45,7 @@ public class ZipkinKafkaCollectorConfigurationTest {
   }
 
   @Test void providesCollectorComponent_whenBootstrapServersEmptyString() {
-    assertThrows(NoSuchBeanDefinitionException.class, () -> {
+    assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
       TestPropertyValues.of("zipkin.collector.kafka.bootstrap-servers:").applyTo(context);
       context.register(
         PropertyPlaceholderAutoConfiguration.class,
@@ -69,7 +69,7 @@ public class ZipkinKafkaCollectorConfigurationTest {
   }
 
   @Test void doesNotProvidesCollectorComponent_whenBootstrapServersSetAndDisabled() {
-    assertThrows(NoSuchBeanDefinitionException.class, () -> {
+    assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
       TestPropertyValues.of("zipkin.collector.kafka.bootstrap-servers:localhost:9092")
         .applyTo(context);
       TestPropertyValues.of("zipkin.collector.kafka.enabled:false").applyTo(context);
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorConfigurationTest.java
index e9f233aec3a..804e91dd00e 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorConfigurationTest.java
+++ b/zipkin-server/src/test/java/zipkin2/server/internal/rabbitmq/ZipkinRabbitMQCollectorConfigurationTest.java
@@ -25,7 +25,7 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 
 public class ZipkinRabbitMQCollectorConfigurationTest {
 
@@ -36,7 +36,7 @@ public class ZipkinRabbitMQCollectorConfigurationTest {
   }
 
   @Test void doesNotProvideCollectorComponent_whenAddressAndUriNotSet() {
-    assertThrows(NoSuchBeanDefinitionException.class, () -> {
+    assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
       context.register(
         PropertyPlaceholderAutoConfiguration.class,
         ZipkinRabbitMQCollectorConfiguration.class,
@@ -47,11 +47,11 @@ public class ZipkinRabbitMQCollectorConfigurationTest {
   }
 
   @Test void doesNotProvideCollectorComponent_whenAddressesAndUriIsEmptyString() {
-    assertThrows(NoSuchBeanDefinitionException.class, () -> {
+    assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
       context = new AnnotationConfigApplicationContext();
       TestPropertyValues.of(
-          "zipkin.collector.rabbitmq.addresses:",
-          "zipkin.collector.rabbitmq.uri:")
+        "zipkin.collector.rabbitmq.addresses:",
+        "zipkin.collector.rabbitmq.uri:")
         .applyTo(context);
       context.register(
         PropertyPlaceholderAutoConfiguration.class,
@@ -80,7 +80,7 @@ public class ZipkinRabbitMQCollectorConfigurationTest {
   }
 
   @Test void doesNotProvidesCollectorComponent_whenAddressesSetAndDisabled() {
-    assertThrows(NoSuchBeanDefinitionException.class, () -> {
+    assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
       context = new AnnotationConfigApplicationContext();
       TestPropertyValues.of("zipkin.collector.rabbitmq.addresses:localhost:1234").applyTo(context);
       TestPropertyValues.of("zipkin.collector.rabbitmq.enabled:false").applyTo(context);
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/throttle/ThrottledStorageComponentTest.java b/zipkin-server/src/test/java/zipkin2/server/internal/throttle/ThrottledStorageComponentTest.java
index 3e290ae673a..ed3df040a77 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/throttle/ThrottledStorageComponentTest.java
+++ b/zipkin-server/src/test/java/zipkin2/server/internal/throttle/ThrottledStorageComponentTest.java
@@ -23,7 +23,7 @@
 import zipkin2.storage.StorageComponent;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -48,7 +48,7 @@ public class ThrottledStorageComponentTest {
   }
 
   @Test void createComponent_withNegativeQueue() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       int queueSize = -1;
       new ThrottledStorageComponent(delegate, registry, tracing, 1, 2, queueSize);
     });
diff --git a/zipkin-server/src/test/java/zipkin2/server/internal/ui/ZipkinUiConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/server/internal/ui/ZipkinUiConfigurationTest.java
index 5e09c0839bd..20f90cf731b 100644
--- a/zipkin-server/src/test/java/zipkin2/server/internal/ui/ZipkinUiConfigurationTest.java
+++ b/zipkin-server/src/test/java/zipkin2/server/internal/ui/ZipkinUiConfigurationTest.java
@@ -35,10 +35,9 @@
 import org.springframework.core.io.ClassPathResource;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 
-public class ZipkinUiConfigurationTest {
+class ZipkinUiConfigurationTest {
 
   AnnotationConfigApplicationContext context;
 
@@ -60,8 +59,7 @@ public class ZipkinUiConfigurationTest {
     ZipkinUiConfiguration ui = new ZipkinUiConfiguration();
     ui.ui = new ZipkinUiProperties();
     ui.lensIndexHtml = new ClassPathResource("does-not-exist.html");
-    assertThatThrownBy(ui::indexService)
-      .isInstanceOf(BeanCreationException.class);
+    assertThatExceptionOfType(BeanCreationException.class).isThrownBy(ui::indexService);
   }
 
   @Test void canOverridesProperty_defaultLookback() {
@@ -112,7 +110,7 @@ public class ZipkinUiConfigurationTest {
   }
 
   @Test void canOverridesProperty_disable() {
-    assertThrows(NoSuchBeanDefinitionException.class, () -> {
+    assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
       context = createContextWithOverridenProperty("zipkin.ui.enabled:false");
 
       context.getBean(ZipkinUiProperties.class);
diff --git a/zipkin-server/src/test/java/zipkin2/storage/mysql/v1/ZipkinMySQLStorageConfigurationTest.java b/zipkin-server/src/test/java/zipkin2/storage/mysql/v1/ZipkinMySQLStorageConfigurationTest.java
index fd196200101..9ebad7de644 100644
--- a/zipkin-server/src/test/java/zipkin2/storage/mysql/v1/ZipkinMySQLStorageConfigurationTest.java
+++ b/zipkin-server/src/test/java/zipkin2/storage/mysql/v1/ZipkinMySQLStorageConfigurationTest.java
@@ -22,7 +22,7 @@
 import zipkin2.server.internal.mysql.Access;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 
 public class ZipkinMySQLStorageConfigurationTest {
 
@@ -35,7 +35,7 @@ public class ZipkinMySQLStorageConfigurationTest {
   }
 
   @Test void doesntProvidesStorageComponent_whenStorageTypeNotMySQL() {
-    assertThrows(NoSuchBeanDefinitionException.class, () -> {
+    assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() -> {
       context = new AnnotationConfigApplicationContext();
       TestPropertyValues.of("zipkin.storage.type:cassandra").applyTo(context);
       Access.registerMySQL(context);
diff --git a/zipkin-storage/elasticsearch/src/test/java/zipkin2/elasticsearch/JsonReadersTest.java b/zipkin-storage/elasticsearch/src/test/java/zipkin2/elasticsearch/JsonReadersTest.java
index fdfb56e9ca5..d518d6c00f7 100644
--- a/zipkin-storage/elasticsearch/src/test/java/zipkin2/elasticsearch/JsonReadersTest.java
+++ b/zipkin-storage/elasticsearch/src/test/java/zipkin2/elasticsearch/JsonReadersTest.java
@@ -19,7 +19,7 @@
 import zipkin2.elasticsearch.internal.JsonReaders;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 import static zipkin2.elasticsearch.internal.JsonReaders.collectValuesNamed;
 import static zipkin2.elasticsearch.internal.JsonSerializers.JSON_FACTORY;
 
@@ -74,7 +74,7 @@ public class JsonReadersTest {
 
   // All elasticsearch results start with an object, not an array.
   @Test void collectValuesNamed_exceptionOnWrongData() throws IOException {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       assertThat(collectValuesNamed(JSON_FACTORY.createParser("[]"), "key")).isEmpty();
     });
   }
diff --git a/zipkin-tests/src/test/java/zipkin2/AnnotationTest.java b/zipkin-tests/src/test/java/zipkin2/AnnotationTest.java
index f87a63750ae..2783471e1b8 100644
--- a/zipkin-tests/src/test/java/zipkin2/AnnotationTest.java
+++ b/zipkin-tests/src/test/java/zipkin2/AnnotationTest.java
@@ -17,7 +17,6 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 
 public class AnnotationTest {
 
@@ -26,7 +25,7 @@ public class AnnotationTest {
 
       Annotation.create(1L, null);
     });
-    assertTrue(exception.getMessage().contains("value"));
+    assertThat(exception.getMessage()).contains("value");
   }
 
   @Test void toString_isNice() {
diff --git a/zipkin-tests/src/test/java/zipkin2/CallTest.java b/zipkin-tests/src/test/java/zipkin2/CallTest.java
index 9d43e250f62..48c0ca8eea5 100644
--- a/zipkin-tests/src/test/java/zipkin2/CallTest.java
+++ b/zipkin-tests/src/test/java/zipkin2/CallTest.java
@@ -31,7 +31,7 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 import static org.mockito.ArgumentMatchers.isA;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.verify;
@@ -249,7 +249,7 @@ void concurrent_executesOrSubmitsOnce() throws InterruptedException {
   }
 
   @Test void onErrorReturn_execute_onError() throws Exception {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       IllegalArgumentException exception = new IllegalArgumentException();
       Call<String> errorCall = errorCall(exception);
 
diff --git a/zipkin-tests/src/test/java/zipkin2/EndpointTest.java b/zipkin-tests/src/test/java/zipkin2/EndpointTest.java
index 72c2b7d6caf..0bb28a4ed9a 100644
--- a/zipkin-tests/src/test/java/zipkin2/EndpointTest.java
+++ b/zipkin-tests/src/test/java/zipkin2/EndpointTest.java
@@ -19,7 +19,6 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 
 public class EndpointTest {
 
@@ -200,7 +199,7 @@ public class EndpointTest {
     Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
       assertThat(Endpoint.newBuilder().port(65536).build().port()).isNull();
     });
-    assertTrue(exception.getMessage().contains("invalid port 65536"));
+    assertThat(exception.getMessage()).contains("invalid port 65536");
   }
 
   /**
@@ -210,7 +209,7 @@ public class EndpointTest {
     Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
       Endpoint.newBuilder().port(65536).build();
     });
-    assertTrue(exception.getMessage().contains("invalid port 65536"));
+    assertThat(exception.getMessage()).contains("invalid port 65536");
   }
 
   /** Catches common error when zero is passed instead of null for a port */
diff --git a/zipkin-tests/src/test/java/zipkin2/SpanBytesDecoderDetectorTest.java b/zipkin-tests/src/test/java/zipkin2/SpanBytesDecoderDetectorTest.java
index f1237e6b6b4..b91f942cf14 100644
--- a/zipkin-tests/src/test/java/zipkin2/SpanBytesDecoderDetectorTest.java
+++ b/zipkin-tests/src/test/java/zipkin2/SpanBytesDecoderDetectorTest.java
@@ -19,7 +19,7 @@
 
 import static java.util.Arrays.asList;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 import static zipkin2.TestObjects.FRONTEND;
 
 public class SpanBytesDecoderDetectorTest {
@@ -53,7 +53,7 @@ public class SpanBytesDecoderDetectorTest {
   }
 
   @Test void decoderForMessage_json_v1_list() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       byte[] message = SpanBytesEncoder.JSON_V1.encodeList(asList(span1, span2));
       SpanBytesDecoderDetector.decoderForMessage(message);
     });
@@ -66,7 +66,7 @@ public class SpanBytesDecoderDetectorTest {
   }
 
   @Test void decoderForListMessage_json_v1_singleItem() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       byte[] message = SpanBytesEncoder.JSON_V1.encode(span1);
       SpanBytesDecoderDetector.decoderForListMessage(message);
     });
@@ -74,7 +74,7 @@ public class SpanBytesDecoderDetectorTest {
 
   /** Single-element reads were for legacy non-list encoding. Don't add new code that does this */
   @Test void decoderForMessage_json_v2() {
-    assertThrows(UnsupportedOperationException.class, () -> {
+    assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
       byte[] message = SpanBytesEncoder.JSON_V2.encode(span1);
       assertThat(SpanBytesDecoderDetector.decoderForMessage(message))
         .isEqualTo(SpanBytesDecoder.JSON_V2);
@@ -82,7 +82,7 @@ public class SpanBytesDecoderDetectorTest {
   }
 
   @Test void decoderForMessage_json_v2_list() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       byte[] message = SpanBytesEncoder.JSON_V2.encodeList(asList(span1, span2));
       SpanBytesDecoderDetector.decoderForMessage(message);
     });
@@ -130,7 +130,7 @@ public class SpanBytesDecoderDetectorTest {
   }
 
   @Test void decoderForListMessage_json_v2_singleItem() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       byte[] message = SpanBytesEncoder.JSON_V2.encode(span1);
       SpanBytesDecoderDetector.decoderForListMessage(message);
     });
@@ -143,7 +143,7 @@ public class SpanBytesDecoderDetectorTest {
   }
 
   @Test void decoderForMessage_thrift_list() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       byte[] message = SpanBytesEncoder.THRIFT.encodeList(asList(span1, span2));
       SpanBytesDecoderDetector.decoderForMessage(message);
     });
@@ -168,7 +168,7 @@ public class SpanBytesDecoderDetectorTest {
   }
 
   @Test void decoderForListMessage_thrift_singleItem() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       byte[] message = SpanBytesEncoder.THRIFT.encode(span1);
       SpanBytesDecoderDetector.decoderForListMessage(message);
     });
@@ -178,7 +178,7 @@ public class SpanBytesDecoderDetectorTest {
    * Single-element reads were for legacy non-list encoding. Don't add new code that does this
    */
   @Test void decoderForMessage_proto3() {
-    assertThrows(UnsupportedOperationException.class, () -> {
+    assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
       byte[] message = SpanBytesEncoder.PROTO3.encode(span1);
       assertThat(SpanBytesDecoderDetector.decoderForMessage(message))
         .isEqualTo(SpanBytesDecoder.PROTO3);
@@ -186,7 +186,7 @@ public class SpanBytesDecoderDetectorTest {
   }
 
   @Test void decoderForMessage_proto3_list() {
-    assertThrows(UnsupportedOperationException.class, () -> {
+    assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> {
       byte[] message = SpanBytesEncoder.PROTO3.encodeList(asList(span1, span2));
       SpanBytesDecoderDetector.decoderForMessage(message);
     });
@@ -206,14 +206,14 @@ public class SpanBytesDecoderDetectorTest {
   }
 
   @Test void decoderForMessage_unknown() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      SpanBytesDecoderDetector.decoderForMessage(new byte[] {'h'});
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
+      SpanBytesDecoderDetector.decoderForMessage(new byte[]{'h'});
     });
   }
 
   @Test void decoderForListMessage_unknown() {
-    assertThrows(IllegalArgumentException.class, () -> {
-      SpanBytesDecoderDetector.decoderForListMessage(new byte[] {'h'});
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
+      SpanBytesDecoderDetector.decoderForListMessage(new byte[]{'h'});
     });
   }
 }
diff --git a/zipkin-tests/src/test/java/zipkin2/SpanTest.java b/zipkin-tests/src/test/java/zipkin2/SpanTest.java
index 09bb07e31b8..ba2f8af3952 100644
--- a/zipkin-tests/src/test/java/zipkin2/SpanTest.java
+++ b/zipkin-tests/src/test/java/zipkin2/SpanTest.java
@@ -21,8 +21,8 @@
 import org.junit.jupiter.api.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 import static org.assertj.core.data.MapEntry.entry;
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static zipkin2.Span.normalizeTraceId;
 import static zipkin2.TestObjects.BACKEND;
 import static zipkin2.TestObjects.FRONTEND;
@@ -416,13 +416,13 @@ public class SpanTest {
   }
 
   @Test void normalizeTraceId_badCharacters() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       normalizeTraceId("000-0000000004d20000000ss000162e");
     });
   }
 
   @Test void traceIdFromLong_invalid() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       base.toBuilder().traceId(0, 0);
     });
   }
@@ -461,43 +461,43 @@ public class SpanTest {
   }
 
   @Test void idFromLong_invalid() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       base.toBuilder().id(0);
     });
   }
 
   @Test void id_emptyInvalid() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       base.toBuilder().id("");
     });
   }
 
   @Test void id_zerosInvalid() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       base.toBuilder().id("0000000000000000");
     });
   }
 
   @Test void parentId_emptyInvalid() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       base.toBuilder().parentId("");
     });
   }
 
   @Test void traceId_emptyInvalid() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       base.toBuilder().traceId("");
     });
   }
 
   @Test void traceId_zerosInvalid() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       base.toBuilder().traceId("0000000000000000");
     });
   }
 
   @Test void traceId_uuidInvalid() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       base.toBuilder().traceId(UUID.randomUUID().toString());
     });
   }
diff --git a/zipkin-tests/src/test/java/zipkin2/codec/SpanBytesDecoderTest.java b/zipkin-tests/src/test/java/zipkin2/codec/SpanBytesDecoderTest.java
index 6dabd50f24d..ca6cd586baf 100644
--- a/zipkin-tests/src/test/java/zipkin2/codec/SpanBytesDecoderTest.java
+++ b/zipkin-tests/src/test/java/zipkin2/codec/SpanBytesDecoderTest.java
@@ -24,7 +24,6 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 import static zipkin2.TestObjects.BACKEND;
 import static zipkin2.TestObjects.TRACE;
 import static zipkin2.codec.SpanBytesEncoderTest.ERROR_SPAN;
@@ -43,8 +42,7 @@ public class SpanBytesDecoderTest {
       byte[] encoded = SpanBytesEncoder.PROTO3.encodeList(TRACE);
       SpanBytesDecoder.PROTO3.decodeList(Arrays.copyOfRange(encoded, 0, 10));
     });
-    assertTrue(exception.getMessage()
-      .contains("Truncated: length 66 > bytes available 8 reading List<Span> from proto3"));
+    assertThat(exception.getMessage()).contains("Truncated: length 66 > bytes available 8 reading List<Span> from proto3");
   }
 
   @Test void niceErrorOnTruncatedSpan_PROTO3() {
@@ -53,8 +51,7 @@ public class SpanBytesDecoderTest {
       byte[] encoded = SpanBytesEncoder.PROTO3.encode(SPAN);
       SpanBytesDecoder.PROTO3.decodeOne(Arrays.copyOfRange(encoded, 0, 10));
     });
-    assertTrue(exception.getMessage()
-      .contains("Truncated: length 179 > bytes available 7 reading Span from proto3"));
+    assertThat(exception.getMessage()).contains("Truncated: length 179 > bytes available 7 reading Span from proto3");
   }
 
   @Test void emptyListOk_JSON_V1() {
@@ -168,7 +165,7 @@ public class SpanBytesDecoderTest {
 
       SpanBytesDecoder.JSON_V2.decodeList(new byte[] {'h', 'e', 'l', 'l', 'o'});
     });
-    assertTrue(exception.getMessage().contains("Malformed reading List<Span> from "));
+    assertThat(exception.getMessage()).contains("Malformed reading List<Span> from ");
   }
 
   @Test void niceErrorOnMalformed_inputSpans_PROTO3() {
@@ -176,8 +173,7 @@ public class SpanBytesDecoderTest {
 
       SpanBytesDecoder.PROTO3.decodeList(new byte[] {'h', 'e', 'l', 'l', 'o'});
     });
-    assertTrue(exception.getMessage()
-      .contains("Truncated: length 101 > bytes available 3 reading List<Span> from proto3"));
+    assertThat(exception.getMessage()).contains("Truncated: length 101 > bytes available 3 reading List<Span> from proto3");
   }
 
   @Test void traceRoundTrip_JSON_V2() {
@@ -306,8 +302,7 @@ public class SpanBytesDecoderTest {
 
       SpanBytesDecoder.JSON_V2.decodeOne(json.getBytes(UTF_8));
     });
-    assertTrue(exception.getMessage()
-      .contains("48485A3953BB6124 should be lower-hex encoded with no prefix"));
+    assertThat(exception.getMessage()).contains("48485A3953BB6124 should be lower-hex encoded with no prefix");
   }
 
   @Test void readsTraceIdHighFromTraceIdField() {
@@ -416,8 +411,7 @@ public class SpanBytesDecoderTest {
 
       SpanBytesDecoder.JSON_V2.decodeOne(json.getBytes(UTF_8));
     });
-    assertTrue(
-      exception.getMessage().contains("Incomplete annotation at $.annotations[0].timestamp"));
+    assertThat(exception.getMessage()).contains("Incomplete annotation at $.annotations[0].timestamp");
   }
 
   @Test void niceErrorOnNull_traceId() {
@@ -431,7 +425,7 @@ public class SpanBytesDecoderTest {
 
       SpanBytesDecoder.JSON_V2.decodeOne(json.getBytes(UTF_8));
     });
-    assertTrue(exception.getMessage().contains("Expected a string but was NULL"));
+    assertThat(exception.getMessage()).contains("Expected a string but was NULL");
   }
 
   @Test void niceErrorOnNull_id() {
@@ -445,7 +439,7 @@ public class SpanBytesDecoderTest {
 
       SpanBytesDecoder.JSON_V2.decodeOne(json.getBytes(UTF_8));
     });
-    assertTrue(exception.getMessage().contains("Expected a string but was NULL"));
+    assertThat(exception.getMessage()).contains("Expected a string but was NULL");
   }
 
   @Test void niceErrorOnNull_tagValue() {
@@ -462,7 +456,7 @@ public class SpanBytesDecoderTest {
 
       SpanBytesDecoder.JSON_V2.decodeOne(json.getBytes(UTF_8));
     });
-    assertTrue(exception.getMessage().contains("No value at $.tags.foo"));
+    assertThat(exception.getMessage()).contains("No value at $.tags.foo");
   }
 
   @Test void niceErrorOnNull_annotationValue() {
@@ -479,7 +473,7 @@ public class SpanBytesDecoderTest {
 
       SpanBytesDecoder.JSON_V2.decodeOne(json.getBytes(UTF_8));
     });
-    assertTrue(exception.getMessage().contains("$.annotations[0].value"));
+    assertThat(exception.getMessage()).contains("$.annotations[0].value");
   }
 
   @Test void niceErrorOnNull_annotationTimestamp() {
@@ -496,7 +490,7 @@ public class SpanBytesDecoderTest {
 
       SpanBytesDecoder.JSON_V2.decodeOne(json.getBytes(UTF_8));
     });
-    assertTrue(exception.getMessage().contains("$.annotations[0].timestamp"));
+    assertThat(exception.getMessage()).contains("$.annotations[0].timestamp");
   }
 
   @Test void readSpan_localEndpoint_noServiceName() {
diff --git a/zipkin-tests/src/test/java/zipkin2/codec/V1SpanBytesDecoderTest.java b/zipkin-tests/src/test/java/zipkin2/codec/V1SpanBytesDecoderTest.java
index 3af23a2ecdd..f9a8ffa0540 100644
--- a/zipkin-tests/src/test/java/zipkin2/codec/V1SpanBytesDecoderTest.java
+++ b/zipkin-tests/src/test/java/zipkin2/codec/V1SpanBytesDecoderTest.java
@@ -24,7 +24,6 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 import static zipkin2.TestObjects.BACKEND;
 import static zipkin2.TestObjects.TRACE;
 import static zipkin2.codec.SpanBytesEncoderTest.LOCAL_SPAN;
@@ -43,8 +42,7 @@ public class V1SpanBytesDecoderTest {
       byte[] encoded = SpanBytesEncoder.THRIFT.encodeList(TRACE);
       SpanBytesDecoder.THRIFT.decodeList(Arrays.copyOfRange(encoded, 0, 10));
     });
-    assertTrue(exception.getMessage()
-      .contains("Truncated: length 8 > bytes available 2 reading List<Span> from TBinary"));
+    assertThat(exception.getMessage()).contains("Truncated: length 8 > bytes available 2 reading List<Span> from TBinary");
   }
 
   @Test void niceErrorOnTruncatedSpan_THRIFT() {
@@ -53,8 +51,7 @@ public class V1SpanBytesDecoderTest {
       byte[] encoded = SpanBytesEncoder.THRIFT.encode(SPAN);
       SpanBytesDecoder.THRIFT.decodeOne(Arrays.copyOfRange(encoded, 0, 10));
     });
-    assertTrue(exception.getMessage()
-      .contains("Truncated: length 8 > bytes available 7 reading Span from TBinary"));
+    assertThat(exception.getMessage()).contains("Truncated: length 8 > bytes available 7 reading Span from TBinary");
   }
 
   @Test void emptyListOk_THRIFT() {
@@ -144,7 +141,7 @@ public class V1SpanBytesDecoderTest {
 
       SpanBytesDecoder.JSON_V1.decodeList(new byte[] {'h', 'e', 'l', 'l', 'o'});
     });
-    assertTrue(exception.getMessage().contains("Malformed reading List<Span> from "));
+    assertThat(exception.getMessage()).contains("Malformed reading List<Span> from ");
   }
 
   @Test void niceErrorOnMalformed_inputSpans_THRIFT() {
@@ -152,8 +149,7 @@ public class V1SpanBytesDecoderTest {
 
       SpanBytesDecoder.THRIFT.decodeList(new byte[] {'h', 'e', 'l', 'l', 'o'});
     });
-    assertTrue(exception.getMessage()
-      .contains("Truncated: length 1 > bytes available 0 reading List<Span> from TBinary"));
+    assertThat(exception.getMessage()).contains("Truncated: length 1 > bytes available 0 reading List<Span> from TBinary");
   }
 
   @Test void traceRoundTrip_JSON_V1() {
@@ -254,8 +250,7 @@ void niceErrorOnUppercase_traceId_JSON_V1() {
 
       SpanBytesDecoder.JSON_V1.decodeOne(json.getBytes(UTF_8));
     });
-    assertTrue(exception.getMessage()
-      .contains("48485A3953BB6124 should be lower-hex encoded with no prefix"));
+    assertThat(exception.getMessage()).contains("48485A3953BB6124 should be lower-hex encoded with no prefix");
   }
 
   @Test void readsTraceIdHighFromTraceIdField() {
@@ -396,8 +391,7 @@ void niceErrorOnUppercase_traceId_JSON_V1() {
 
       SpanBytesDecoder.JSON_V1.decodeOne(json.getBytes(UTF_8));
     });
-    assertTrue(
-      exception.getMessage().contains("Incomplete annotation at $.annotations[0].timestamp"));
+    assertThat(exception.getMessage()).contains("Incomplete annotation at $.annotations[0].timestamp");
   }
 
   @Test void niceErrorOnNull_traceId() {
@@ -412,7 +406,7 @@ void niceErrorOnUppercase_traceId_JSON_V1() {
 
       SpanBytesDecoder.JSON_V1.decodeOne(json.getBytes(UTF_8));
     });
-    assertTrue(exception.getMessage().contains("Expected a string but was NULL"));
+    assertThat(exception.getMessage()).contains("Expected a string but was NULL");
   }
 
   @Test void niceErrorOnNull_id() {
@@ -427,7 +421,7 @@ void niceErrorOnUppercase_traceId_JSON_V1() {
 
       SpanBytesDecoder.JSON_V1.decodeOne(json.getBytes(UTF_8));
     });
-    assertTrue(exception.getMessage().contains("Expected a string but was NULL"));
+    assertThat(exception.getMessage()).contains("Expected a string but was NULL");
   }
 
   @Test void niceErrorOnNull_annotationValue() {
@@ -445,7 +439,7 @@ void niceErrorOnUppercase_traceId_JSON_V1() {
 
       SpanBytesDecoder.JSON_V1.decodeOne(json.getBytes(UTF_8));
     });
-    assertTrue(exception.getMessage().contains("$.annotations[0].value"));
+    assertThat(exception.getMessage()).contains("$.annotations[0].value");
   }
 
   @Test void niceErrorOnNull_annotationTimestamp() {
@@ -463,7 +457,7 @@ void niceErrorOnUppercase_traceId_JSON_V1() {
 
       SpanBytesDecoder.JSON_V1.decodeOne(json.getBytes(UTF_8));
     });
-    assertTrue(exception.getMessage().contains("$.annotations[0].timestamp"));
+    assertThat(exception.getMessage()).contains("$.annotations[0].timestamp");
   }
 
   @Test void readSpan_localEndpoint_noServiceName() {
diff --git a/zipkin-tests/src/test/java/zipkin2/internal/AggregateCallTest.java b/zipkin-tests/src/test/java/zipkin2/internal/AggregateCallTest.java
index 70277e53aef..9d7c2e851e5 100644
--- a/zipkin-tests/src/test/java/zipkin2/internal/AggregateCallTest.java
+++ b/zipkin-tests/src/test/java/zipkin2/internal/AggregateCallTest.java
@@ -34,7 +34,7 @@
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.isA;
 import static org.mockito.Mockito.doAnswer;
@@ -50,7 +50,7 @@ public class AggregateCallTest {
   @Mock Callback<Void> callback;
 
   @Test void newVoidCall_emptyNotAllowed() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       AggregateCall.newVoidCall(asList());
     });
   }
diff --git a/zipkin-tests/src/test/java/zipkin2/internal/JsonCodecTest.java b/zipkin-tests/src/test/java/zipkin2/internal/JsonCodecTest.java
index 019de0a65c9..321042bbe5c 100644
--- a/zipkin-tests/src/test/java/zipkin2/internal/JsonCodecTest.java
+++ b/zipkin-tests/src/test/java/zipkin2/internal/JsonCodecTest.java
@@ -20,7 +20,6 @@
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 import static zipkin2.internal.JsonCodec.exceptionReading;
 
 public class JsonCodecTest {
@@ -47,9 +46,7 @@ class Foo {
 
       new Foo().toString(); // cause the exception
     });
-    assertTrue(exception.getMessage()
-      .contains(
-        "Bug found using FooWriter to write Foo as json. Wrote 1/2 bytes: a")); // cause the exception
+    assertThat(exception.getMessage()).contains("Bug found using FooWriter to write Foo as json. Wrote 1/2 bytes: a"); // cause the exception
   }
 
   @Test void doesntStackOverflowOnToBufferWriterBug_Overflow() {
@@ -76,9 +73,7 @@ class Foo {
 
       new Foo().toString(); // cause the exception
     });
-    assertTrue(exception.getMessage()
-      .contains(
-        "Bug found using FooWriter to write Foo as json. Wrote 2/2 bytes: ab")); // cause the exception
+    assertThat(exception.getMessage()).contains("Bug found using FooWriter to write Foo as json. Wrote 2/2 bytes: ab"); // cause the exception
   }
 
   @Test void exceptionReading_malformedJsonWraps() {
diff --git a/zipkin-tests/src/test/java/zipkin2/internal/SpanNodeTest.java b/zipkin-tests/src/test/java/zipkin2/internal/SpanNodeTest.java
index 5214c8fd857..bf6f4446d1c 100644
--- a/zipkin-tests/src/test/java/zipkin2/internal/SpanNodeTest.java
+++ b/zipkin-tests/src/test/java/zipkin2/internal/SpanNodeTest.java
@@ -26,7 +26,7 @@
 
 import static java.util.Arrays.asList;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
 
 public class SpanNodeTest {
   List<String> messages = new ArrayList<>();
@@ -43,7 +43,7 @@ public class SpanNodeTest {
   };
 
   @Test void addChild_nullNotAllowed() {
-    assertThrows(NullPointerException.class, () -> {
+    assertThatExceptionOfType(NullPointerException.class).isThrownBy(() -> {
       Span.Builder builder = Span.newBuilder().traceId("a");
       SpanNode a = new SpanNode(builder.id("a").build());
       a.addChild(null);
@@ -51,7 +51,7 @@ public class SpanNodeTest {
   }
 
   @Test void addChild_selfNotAllowed() {
-    assertThrows(IllegalArgumentException.class, () -> {
+    assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> {
       Span.Builder builder = Span.newBuilder().traceId("a");
       SpanNode a = new SpanNode(builder.id("a").build());
       a.addChild(a);
diff --git a/zipkin-tests/src/test/java/zipkin2/storage/QueryRequestTest.java b/zipkin-tests/src/test/java/zipkin2/storage/QueryRequestTest.java
index ec73a7c08bc..9200a2ff25b 100644
--- a/zipkin-tests/src/test/java/zipkin2/storage/QueryRequestTest.java
+++ b/zipkin-tests/src/test/java/zipkin2/storage/QueryRequestTest.java
@@ -24,7 +24,6 @@
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.entry;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
 
 public class QueryRequestTest {
   QueryRequest.Builder queryBuilder =
@@ -105,7 +104,7 @@ public class QueryRequestTest {
 
       queryBuilder.endTs(0L).build();
     });
-    assertTrue(exception.getMessage().contains("endTs <= 0"));
+    assertThat(exception.getMessage()).contains("endTs <= 0");
   }
 
   @Test void lookbackMustBePositive() {
@@ -113,7 +112,7 @@ public class QueryRequestTest {
 
       queryBuilder.lookback(0).build();
     });
-    assertTrue(exception.getMessage().contains("lookback <= 0"));
+    assertThat(exception.getMessage()).contains("lookback <= 0");
   }
 
   @Test void limitMustBePositive() {
@@ -121,7 +120,7 @@ public class QueryRequestTest {
 
       queryBuilder.limit(0).build();
     });
-    assertTrue(exception.getMessage().contains("limit <= 0"));
+    assertThat(exception.getMessage()).contains("limit <= 0");
   }
 
   @Test void annotationQuery_roundTrip() {
@@ -162,7 +161,7 @@ public class QueryRequestTest {
 
       queryBuilder.minDuration(0L).build();
     });
-    assertTrue(exception.getMessage().contains("minDuration <= 0"));
+    assertThat(exception.getMessage()).contains("minDuration <= 0");
   }
 
   @Test void maxDuration_onlyWithMinDuration() {
@@ -170,7 +169,7 @@ public class QueryRequestTest {
 
       queryBuilder.maxDuration(0L).build();
     });
-    assertTrue(exception.getMessage().contains("maxDuration is only valid with minDuration"));
+    assertThat(exception.getMessage()).contains("maxDuration is only valid with minDuration");
   }
 
   @Test void maxDuration_greaterThanOrEqualToMinDuration() {
@@ -178,7 +177,7 @@ public class QueryRequestTest {
 
       queryBuilder.minDuration(1L).maxDuration(0L).build();
     });
-    assertTrue(exception.getMessage().contains("maxDuration < minDuration"));
+    assertThat(exception.getMessage()).contains("maxDuration < minDuration");
   }
 
   @Test void test_matchesTimestamp() {