Index: test/unit/org/openstreetmap/josm/data/osm/search/SearchCompilerTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/data/osm/search/SearchCompilerTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/data/osm/search/SearchCompilerTest.java	(working copy)
@@ -5,6 +5,8 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import java.lang.reflect.Field;
 import java.nio.charset.StandardCharsets;
@@ -18,7 +20,6 @@
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -60,12 +61,6 @@
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
     public JOSMTestRules test = new JOSMTestRules().preferences().timeout(30000);
 
-    /**
-     * Rule to assert exception message.
-     */
-    @Rule
-    public ExpectedException expectedEx = ExpectedException.none();
-
     private static final class SearchContext {
         final DataSet ds = new DataSet();
         final Node n1 = new Node(LatLon.ZERO);
@@ -426,9 +421,8 @@
      */
     @Test
     public void testFooTypeBar() throws SearchParseError {
-        expectedEx.expect(SearchParseError.class);
-        expectedEx.expectMessage("<html>Expecting <code>:</code> after <i>type</i></html>");
-        SearchCompiler.compile("foo type bar");
+        Exception e = assertThrows(SearchParseError.class, () -> SearchCompiler.compile("foo type bar"));
+        assertEquals("<html>Expecting <code>:</code> after <i>type</i></html>", e.getMessage());
     }
 
     /**
@@ -552,7 +546,7 @@
      */
     @Test
     public void testEnumExactKeyValueMode() {
-        TestUtils.superficialEnumCodeCoverage(ExactKeyValue.Mode.class);
+        assertDoesNotThrow(() -> TestUtils.superficialEnumCodeCoverage(ExactKeyValue.Mode.class));
     }
 
     /**
Index: test/unit/org/openstreetmap/josm/data/validation/tests/OpeningHourTestTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/data/validation/tests/OpeningHourTestTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/data/validation/tests/OpeningHourTestTest.java	(working copy)
@@ -4,9 +4,9 @@
 import static org.CustomMatchers.hasSize;
 import static org.CustomMatchers.isEmpty;
 import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 import java.util.Arrays;
Index: test/unit/org/openstreetmap/josm/data/validation/tests/UnconnectedWaysTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/data/validation/tests/UnconnectedWaysTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/data/validation/tests/UnconnectedWaysTest.java	(working copy)
@@ -3,7 +3,7 @@
 
 import static org.CustomMatchers.hasSize;
 import static org.CustomMatchers.isEmpty;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
Index: test/unit/org/openstreetmap/josm/data/validation/tests/UntaggedNodeTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/data/validation/tests/UntaggedNodeTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/data/validation/tests/UntaggedNodeTest.java	(working copy)
@@ -3,7 +3,7 @@
 
 import static org.CustomMatchers.hasSize;
 import static org.CustomMatchers.isEmpty;
-import static org.junit.Assert.assertThat;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 import java.io.InputStream;
 
Index: test/unit/org/openstreetmap/josm/gui/NavigatableComponentTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/gui/NavigatableComponentTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/gui/NavigatableComponentTest.java	(working copy)
@@ -1,8 +1,8 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui;
 
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
 
 import java.awt.Point;
 import java.awt.Rectangle;
Index: test/unit/org/openstreetmap/josm/gui/layer/LayerManagerTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/gui/layer/LayerManagerTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/gui/layer/LayerManagerTest.java	(working copy)
@@ -1,7 +1,8 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.layer;
-
-import static org.hamcrest.CoreMatchers.any;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -9,6 +10,8 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.openstreetmap.josm.testutils.ThrowableRootCauseMatcher.hasRootCause;
 
 import java.awt.Component;
 import java.awt.Graphics;
@@ -22,7 +25,6 @@
 import javax.swing.Icon;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
@@ -32,7 +34,6 @@
 import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
 import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
 import org.openstreetmap.josm.gui.util.GuiHelper;
-import org.openstreetmap.josm.testutils.ExpectedRootException;
 import org.openstreetmap.josm.tools.bugreport.ReportedException;
 
 /**
@@ -162,12 +163,6 @@
     protected LayerManager layerManager;
 
     /**
-     * Rule used to expect exceptions.
-     */
-    @Rule
-    public ExpectedRootException thrown = ExpectedRootException.none();
-
-    /**
      * Set up test layer manager.
      */
     @Before
@@ -227,13 +222,13 @@
      */
     @Test
     public void testAddLayerFails() {
-        thrown.expect(ReportedException.class);
-        thrown.expectCause(any(InvocationTargetException.class));
-        thrown.expectRootCause(any(IllegalArgumentException.class));
-
-        TestLayer layer1 = new TestLayer();
-        layerManager.addLayer(layer1);
-        layerManager.addLayer(layer1);
+        Exception e = assertThrows(ReportedException.class, () -> {
+            TestLayer layer1 = new TestLayer();
+            layerManager.addLayer(layer1);
+            layerManager.addLayer(layer1);
+        });
+        assertThat(e.getCause(), is(instanceOf(InvocationTargetException.class)));
+        assertThat(e.getCause(), hasRootCause(is(instanceOf(IllegalArgumentException.class))));
     }
 
     /**
@@ -241,17 +236,17 @@
      */
     @Test
     public void testAddLayerIllegalPosition() {
-        thrown.expect(ReportedException.class);
-        thrown.expectCause(any(InvocationTargetException.class));
-        thrown.expectRootCause(any(IndexOutOfBoundsException.class));
-
-        TestLayer layer1 = new TestLayer() {
-            @Override
-            public LayerPositionStrategy getDefaultLayerPosition() {
-                return manager -> 42;
-            }
-        };
-        layerManager.addLayer(layer1);
+        Exception e = assertThrows(ReportedException.class, () -> {
+            TestLayer layer1 = new TestLayer() {
+                @Override
+                public LayerPositionStrategy getDefaultLayerPosition() {
+                    return manager -> 42;
+                }
+            };
+            layerManager.addLayer(layer1);
+        });
+        assertThat(e.getCause(), is(instanceOf(InvocationTargetException.class)));
+        assertThat(e.getCause(), hasRootCause(is(instanceOf(IndexOutOfBoundsException.class))));
     }
 
     /**
@@ -308,15 +303,15 @@
      */
     @Test
     public void testMoveLayerFailsRange() {
-        thrown.expect(ReportedException.class);
-        thrown.expectCause(any(InvocationTargetException.class));
-        thrown.expectRootCause(any(IndexOutOfBoundsException.class));
-
-        TestLayer layer1 = new TestLayer();
-        TestLayer layer2 = new TestLayer();
-        layerManager.addLayer(layer1);
-        layerManager.addLayer(layer2);
-        layerManager.moveLayer(layer2, 2);
+        Exception e = assertThrows(ReportedException.class, () -> {
+            TestLayer layer1 = new TestLayer();
+            TestLayer layer2 = new TestLayer();
+            layerManager.addLayer(layer1);
+            layerManager.addLayer(layer2);
+            layerManager.moveLayer(layer2, 2);
+        });
+        assertThat(e.getCause(), is(instanceOf(InvocationTargetException.class)));
+        assertThat(e.getCause(), hasRootCause(is(instanceOf(IndexOutOfBoundsException.class))));
     }
 
     /**
@@ -324,14 +319,14 @@
      */
     @Test
     public void testMoveLayerFailsNotInList() {
-        thrown.expect(ReportedException.class);
-        thrown.expectCause(any(InvocationTargetException.class));
-        thrown.expectRootCause(any(IllegalArgumentException.class));
-
-        TestLayer layer1 = new TestLayer();
-        TestLayer layer2 = new TestLayer();
-        layerManager.addLayer(layer1);
-        layerManager.moveLayer(layer2, 0);
+        Exception e = assertThrows(ReportedException.class, () -> {
+            TestLayer layer1 = new TestLayer();
+            TestLayer layer2 = new TestLayer();
+            layerManager.addLayer(layer1);
+            layerManager.moveLayer(layer2, 0);
+        });
+        assertThat(e.getCause(), is(instanceOf(InvocationTargetException.class)));
+        assertThat(e.getCause(), hasRootCause(is(instanceOf(IllegalArgumentException.class))));
     }
 
     /**
Index: test/unit/org/openstreetmap/josm/gui/mappaint/RenderingCLIAreaTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/gui/mappaint/RenderingCLIAreaTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/gui/mappaint/RenderingCLIAreaTest.java	(working copy)
@@ -2,6 +2,7 @@
 package org.openstreetmap.josm.gui.mappaint;
 
 import static org.CustomMatchers.isFP;
+import static org.hamcrest.MatcherAssert.assertThat;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -11,7 +12,6 @@
 import org.hamcrest.CoreMatchers;
 import org.hamcrest.Matcher;
 import org.junit.Rule;
-import org.junit.Assert;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -69,8 +69,8 @@
         LatLon aFeldberg = bFeldberg.getMin();
         LatLon aFeldberg200mRight = new LatLon(aFeldberg.lat(), 13.433008399004041);
         LatLon aFeldberg150mUp = new LatLon(53.33134745249311, aFeldberg.lon());
-        Assert.assertThat(aFeldberg.greatCircleDistance(aFeldberg200mRight), isFP(200.0, 0.01));
-        Assert.assertThat(aFeldberg.greatCircleDistance(aFeldberg150mUp), isFP(150.0, 0.01));
+        assertThat(aFeldberg.greatCircleDistance(aFeldberg200mRight), isFP(200.0, 0.01));
+        assertThat(aFeldberg.greatCircleDistance(aFeldberg150mUp), isFP(150.0, 0.01));
 
         Bounds bFeldberg200x150m = new Bounds(
                 bFeldberg.getMin(), new LatLon(aFeldberg150mUp.lat(), aFeldberg200mRight.lon()));
@@ -163,7 +163,7 @@
         RenderingCLI cli = new RenderingCLI();
         cli.parseArguments(args);
         RenderingCLI.RenderingArea ra = cli.determineRenderingArea(null);
-        Assert.assertThat(ra.scale, scaleMatcher);
-        Assert.assertThat(ra.bounds, boundsMatcher);
+        assertThat(ra.scale, scaleMatcher);
+        assertThat(ra.bounds, boundsMatcher);
     }
 }
Index: test/unit/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReaderTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReaderTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReaderTest.java	(working copy)
@@ -2,8 +2,8 @@
 package org.openstreetmap.josm.gui.tagging.presets;
 
 import static org.CustomMatchers.hasSize;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
Index: test/unit/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandlerTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandlerTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandlerTest.java	(working copy)
@@ -1,9 +1,12 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.io.remotecontrol.handler;
 
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
@@ -16,14 +19,7 @@
  * Unit tests of {@link AddNodeHandler} class.
  */
 public class AddNodeHandlerTest {
-
     /**
-     * Rule used for tests throwing exceptions.
-     */
-    @Rule
-    public ExpectedException thrown = ExpectedException.none();
-
-    /**
      * Setup test.
      */
     @Rule
@@ -39,58 +35,49 @@
 
     /**
      * Unit test for bad request - no layer.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testBadRequestNoLayer() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("There is no layer opened to add node");
-        newHandler("https://localhost?lat=0&lon=0").handle();
+    public void testBadRequestNoLayer() {
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("https://localhost?lat=0&lon=0").handle());
+        assertEquals("There is no layer opened to add node", e.getMessage());
     }
 
     /**
      * Unit test for bad request - no param.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testBadRequestNoParam() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("NumberFormatException (empty String)");
+    public void testBadRequestNoParam() {
         OsmDataLayer layer = new OsmDataLayer(new DataSet(), "", null);
         MainApplication.getLayerManager().addLayer(layer);
-        newHandler(null).handle();
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler(null).handle());
+        assertEquals("NumberFormatException (empty String)", e.getMessage());
     }
 
     /**
      * Unit test for bad request - invalid URL.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testBadRequestInvalidUrl() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("The following keys are mandatory, but have not been provided: lat, lon");
-        newHandler("invalid_url").handle();
+    public void testBadRequestInvalidUrl() {
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("invalid_url").handle());
+        assertEquals("The following keys are mandatory, but have not been provided: lat, lon", e.getMessage());
     }
 
     /**
      * Unit test for bad request - incomplete URL.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testBadRequestIncompleteUrl() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("The following keys are mandatory, but have not been provided: lat, lon");
-        newHandler("https://localhost").handle();
+    public void testBadRequestIncompleteUrl() {
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("https://localhost").handle());
+        assertEquals("The following keys are mandatory, but have not been provided: lat, lon", e.getMessage());
     }
 
     /**
      * Unit test for nominal request - local data file.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testNominalRequest() throws Exception {
+    public void testNominalRequest() {
         OsmDataLayer layer = new OsmDataLayer(new DataSet(), "", null);
         MainApplication.getLayerManager().addLayer(layer);
-        newHandler("https://localhost?lat=0&lon=0").handle();
+        assertDoesNotThrow(() -> newHandler("https://localhost?lat=0&lon=0").handle());
     }
 }
Index: test/unit/org/openstreetmap/josm/io/remotecontrol/handler/AddWayHandlerTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/io/remotecontrol/handler/AddWayHandlerTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/io/remotecontrol/handler/AddWayHandlerTest.java	(working copy)
@@ -1,9 +1,12 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.io.remotecontrol.handler;
 
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
@@ -16,14 +19,7 @@
  * Unit tests of {@link AddWayHandler} class.
  */
 public class AddWayHandlerTest {
-
     /**
-     * Rule used for tests throwing exceptions.
-     */
-    @Rule
-    public ExpectedException thrown = ExpectedException.none();
-
-    /**
      * Setup test.
      */
     @Rule
@@ -39,27 +35,23 @@
 
     /**
      * Unit test for bad request - no layer.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testBadRequestNoLayer() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("There is no layer opened to add way");
-        newHandler("https://localhost?way=0,0;1,1").handle();
+    public void testBadRequestNoLayer() {
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("https://localhost?way=0,0;1,1").handle());
+        assertEquals("There is no layer opened to add way", e.getMessage());
     }
 
     /**
      * Unit test for bad request - no param.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testBadRequestNoParam() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("Invalid coordinates: []");
+    public void testBadRequestNoParam() {
         OsmDataLayer layer = new OsmDataLayer(new DataSet(), "", null);
         try {
             MainApplication.getLayerManager().addLayer(layer);
-            newHandler(null).handle();
+            Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler(null).handle());
+            assertEquals("Invalid coordinates: []", e.getMessage());
         } finally {
             MainApplication.getLayerManager().removeLayer(layer);
         }
@@ -67,36 +59,31 @@
 
     /**
      * Unit test for bad request - invalid URL.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testBadRequestInvalidUrl() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("The following keys are mandatory, but have not been provided: way");
-        newHandler("invalid_url").handle();
+    public void testBadRequestInvalidUrl() {
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("invalid_url").handle());
+        assertEquals("The following keys are mandatory, but have not been provided: way", e.getMessage());
     }
 
     /**
      * Unit test for bad request - incomplete URL.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testBadRequestIncompleteUrl() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("The following keys are mandatory, but have not been provided: way");
-        newHandler("https://localhost").handle();
+    public void testBadRequestIncompleteUrl() {
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("https://localhost").handle());
+        assertEquals("The following keys are mandatory, but have not been provided: way", e.getMessage());
     }
 
     /**
      * Unit test for nominal request - local data file.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testNominalRequest() throws Exception {
+    public void testNominalRequest() {
         OsmDataLayer layer = new OsmDataLayer(new DataSet(), "", null);
         try {
             MainApplication.getLayerManager().addLayer(layer);
-            newHandler("https://localhost?way=0,0;1,1").handle();
+            assertDoesNotThrow(() -> newHandler("https://localhost?way=0,0;1,1").handle());
         } finally {
             MainApplication.getLayerManager().removeLayer(layer);
         }
Index: test/unit/org/openstreetmap/josm/io/remotecontrol/handler/ImageryHandlerTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/io/remotecontrol/handler/ImageryHandlerTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/io/remotecontrol/handler/ImageryHandlerTest.java	(working copy)
@@ -2,8 +2,10 @@
 package org.openstreetmap.josm.io.remotecontrol.handler;
 
 import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import java.util.Arrays;
 import java.util.List;
@@ -10,7 +12,6 @@
 
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
 import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerBadRequestException;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
@@ -21,14 +22,7 @@
  * Unit tests of {@link ImageryHandler} class.
  */
 public class ImageryHandlerTest {
-
     /**
-     * Rule used for tests throwing exceptions.
-     */
-    @Rule
-    public ExpectedException thrown = ExpectedException.none();
-
-    /**
      * Setup test.
      */
     @Rule
@@ -44,44 +38,38 @@
 
     /**
      * Unit test for bad request - no param.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testBadRequestNoParam() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("Parameter must not be null");
-        newHandler(null).handle();
+    public void testBadRequestNoParam() {
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler(null).handle());
+        assertEquals("Parameter must not be null", e.getMessage());
+
     }
 
     /**
      * Unit test for bad request - invalid URL.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testBadRequestInvalidUrl() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("The following keys are mandatory, but have not been provided: url");
-        newHandler("invalid_url").handle();
+    public void testBadRequestInvalidUrl() {
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("invalid_url").handle());
+        assertEquals("The following keys are mandatory, but have not been provided: url", e.getMessage());
     }
 
     /**
      * Unit test for bad request - incomplete URL.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testBadRequestIncompleteUrl() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("The following keys are mandatory, but have not been provided: url");
-        newHandler("https://localhost").handle();
+    public void testBadRequestIncompleteUrl() {
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("https://localhost").handle());
+        assertEquals("The following keys are mandatory, but have not been provided: url", e.getMessage());
     }
 
     /**
      * Unit test for nominal request - local data file.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testNominalRequest() throws Exception {
-        newHandler("https://localhost?url=foo").handle();
+    public void testNominalRequest() {
+        assertDoesNotThrow(() -> newHandler("https://localhost?url=foo").handle());
     }
 
     /**
Index: test/unit/org/openstreetmap/josm/io/remotecontrol/handler/ImportHandlerTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/io/remotecontrol/handler/ImportHandlerTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/io/remotecontrol/handler/ImportHandlerTest.java	(working copy)
@@ -2,12 +2,13 @@
 package org.openstreetmap.josm.io.remotecontrol.handler;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import java.io.File;
 
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
@@ -21,14 +22,7 @@
  * Unit tests of {@link ImportHandler} class.
  */
 public class ImportHandlerTest {
-
     /**
-     * Rule used for tests throwing exceptions.
-     */
-    @Rule
-    public ExpectedException thrown = ExpectedException.none();
-
-    /**
      * Setup test.
      */
     @Rule
@@ -58,9 +52,8 @@
      */
     @Test
     public void testBadRequestNoParam() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("MalformedURLException: null");
-        newHandler(null).handle();
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler(null).handle());
+        assertEquals("MalformedURLException: null", e.getMessage());
     }
 
     /**
@@ -69,9 +62,8 @@
      */
     @Test
     public void testBadRequestInvalidUrl() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("MalformedURLException: no protocol: invalid_url");
-        newHandler("https://localhost?url=invalid_url").handle();
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("https://localhost?url=invalid_url").handle());
+        assertEquals("MalformedURLException: no protocol: invalid_url", e.getMessage());
     }
 
     /**
@@ -80,9 +72,8 @@
      */
     @Test
     public void testBadRequestIncompleteUrl() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("The following keys are mandatory, but have not been provided: url");
-        newHandler("https://localhost").handle();
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("https://localhost").handle());
+        assertEquals("The following keys are mandatory, but have not been provided: url", e.getMessage());
     }
 
     /**
@@ -93,7 +84,7 @@
     public void testNominalRequest() throws Exception {
         String url = new File(TestUtils.getRegressionDataFile(11957, "data.osm")).toURI().toURL().toExternalForm();
         try {
-            newHandler("https://localhost?url=" + Utils.encodeUrl(url)).handle();
+            assertDoesNotThrow(() -> newHandler("https://localhost?url=" + Utils.encodeUrl(url)).handle());
         } finally {
             for (OsmDataLayer layer : MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class)) {
                 MainApplication.getLayerManager().removeLayer(layer);
Index: test/unit/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandlerTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandlerTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/io/remotecontrol/handler/LoadAndZoomHandlerTest.java	(working copy)
@@ -1,9 +1,12 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.io.remotecontrol.handler;
 
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerBadRequestException;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
@@ -13,14 +16,7 @@
  * Unit tests of {@link LoadAndZoomHandler} class.
  */
 public class LoadAndZoomHandlerTest {
-
     /**
-     * Rule used for tests throwing exceptions.
-     */
-    @Rule
-    public ExpectedException thrown = ExpectedException.none();
-
-    /**
      * Setup test.
      */
     @Rule
@@ -40,9 +36,8 @@
      */
     @Test
     public void testBadRequestNoParam() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("NumberFormatException (empty String)");
-        newHandler(null).handle();
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler(null).handle());
+        assertEquals("NumberFormatException (empty String)", e.getMessage());
     }
 
     /**
@@ -51,9 +46,8 @@
      */
     @Test
     public void testBadRequestInvalidUrl() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("The following keys are mandatory, but have not been provided: bottom, top, left, right");
-        newHandler("invalid_url").handle();
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("invalid_url").handle());
+        assertEquals("The following keys are mandatory, but have not been provided: bottom, top, left, right", e.getMessage());
     }
 
     /**
@@ -62,9 +56,8 @@
      */
     @Test
     public void testBadRequestIncompleteUrl() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("The following keys are mandatory, but have not been provided: bottom, top, left, right");
-        newHandler("https://localhost").handle();
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("https://localhost").handle());
+        assertEquals("The following keys are mandatory, but have not been provided: bottom, top, left, right", e.getMessage());
     }
 
     /**
@@ -73,6 +66,6 @@
      */
     @Test
     public void testNominalRequest() throws Exception {
-        newHandler("https://localhost?bottom=0&top=0&left=1&right=1").handle();
+        assertDoesNotThrow(() -> newHandler("https://localhost?bottom=0&top=0&left=1&right=1").handle());
     }
 }
Index: test/unit/org/openstreetmap/josm/io/remotecontrol/handler/LoadObjectHandlerTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/io/remotecontrol/handler/LoadObjectHandlerTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/io/remotecontrol/handler/LoadObjectHandlerTest.java	(working copy)
@@ -1,9 +1,12 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.io.remotecontrol.handler;
 
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerBadRequestException;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
@@ -13,14 +16,7 @@
  * Unit tests of {@link LoadObjectHandler} class.
  */
 public class LoadObjectHandlerTest {
-
     /**
-     * Rule used for tests throwing exceptions.
-     */
-    @Rule
-    public ExpectedException thrown = ExpectedException.none();
-
-    /**
      * Setup test.
      */
     @Rule
@@ -36,41 +32,35 @@
 
     /**
      * Unit test for bad request - no param.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testBadRequestNoParam() throws Exception {
-        newHandler(null).handle();
+    public void testBadRequestNoParam() {
+        assertDoesNotThrow(() -> newHandler(null).handle());
     }
 
     /**
      * Unit test for bad request - invalid URL.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testBadRequestInvalidUrl() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("The following keys are mandatory, but have not been provided: objects");
-        newHandler("invalid_url").handle();
+    public void testBadRequestInvalidUrl() {
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("invalid_url").handle());
+        assertEquals("The following keys are mandatory, but have not been provided: objects", e.getMessage());
     }
 
     /**
      * Unit test for bad request - incomplete URL.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testBadRequestIncompleteUrl() throws Exception {
-        thrown.expect(RequestHandlerBadRequestException.class);
-        thrown.expectMessage("The following keys are mandatory, but have not been provided: objects");
-        newHandler("https://localhost").handle();
+    public void testBadRequestIncompleteUrl() {
+        Exception e = assertThrows(RequestHandlerBadRequestException.class, () -> newHandler("https://localhost").handle());
+        assertEquals("The following keys are mandatory, but have not been provided: objects", e.getMessage());
     }
 
     /**
      * Unit test for nominal request - local data file.
-     * @throws Exception if any error occurs
      */
     @Test
-    public void testNominalRequest() throws Exception {
-        newHandler("https://localhost?objects=foo,bar").handle();
+    public void testNominalRequest() {
+        assertDoesNotThrow(() -> newHandler("https://localhost?objects=foo,bar").handle());
     }
 }
Index: test/unit/org/openstreetmap/josm/testutils/ExpectedRootException.java
===================================================================
--- test/unit/org/openstreetmap/josm/testutils/ExpectedRootException.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/testutils/ExpectedRootException.java	(working copy)
@@ -16,7 +16,9 @@
  * This class is needed to add {@link #expectRootCause} method, which has been rejected by JUnit developers,
  * and {@code ExpectedException} cannot be extended because it has a private constructor.
  * @see <a href="https://github.com/junit-team/junit4/pull/778">Github pull request</a>
+ * @deprecated Use matchers instead with the return from {@link org.junit.jupiter.api.Assertions#assertThrows}
  */
+@Deprecated
 public final class ExpectedRootException implements TestRule {
 
     private final ExpectedException rule = ExpectedException.none();
Index: test/unit/org/openstreetmap/josm/tools/GeoUrlToBoundsTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/tools/GeoUrlToBoundsTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/tools/GeoUrlToBoundsTest.java	(working copy)
@@ -2,8 +2,8 @@
 package org.openstreetmap.josm.tools;
 
 import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
 
 import org.junit.Test;
 
Index: test/unit/org/openstreetmap/josm/tools/OptionParserTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/tools/OptionParserTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/tools/OptionParserTest.java	(working copy)
@@ -4,6 +4,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -11,27 +12,20 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.ExpectedException;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 import org.openstreetmap.josm.tools.OptionParser.OptionCount;
 import org.openstreetmap.josm.tools.OptionParser.OptionParseException;
 
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
 /**
  * Test for {@link OptionParser}
  * @author Michael Zangl
  */
 public class OptionParserTest {
-
     /**
-     * Rule used for tests throwing exceptions.
-     */
-    @Rule
-    public ExpectedException thrown = ExpectedException.none();
-
-    /**
      * Setup test.
      */
     @Rule
@@ -41,31 +35,27 @@
     // A reason for moving to jupiter...
     @Test
     public void testEmptyParserRejectsLongopt() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: unrecognized option '--long'");
-        new OptionParser("test").parseOptions(Arrays.asList("--long"));
+        Exception e = assertThrows(OptionParseException.class, () -> new OptionParser("test").parseOptions(Arrays.asList("--long")));
+        assertEquals("test: unrecognized option '--long'", e.getMessage());
     }
 
     @Test
     public void testEmptyParserRejectsShortopt() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: unrecognized option '-s'");
-        new OptionParser("test").parseOptions(Arrays.asList("-s"));
+        Exception e = assertThrows(OptionParseException.class, () -> new OptionParser("test").parseOptions(Arrays.asList("-s")));
+        assertEquals("test: unrecognized option '-s'", e.getMessage());
     }
 
     @Test
     public void testParserRejectsWrongShortopt() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: unrecognized option '-s'");
-        new OptionParser("test").addFlagParameter("test", this::nop).addShortAlias("test", "t")
-                .parseOptions(Arrays.asList("-s"));
+        Exception e = assertThrows(OptionParseException.class, () -> new OptionParser("test").addFlagParameter("test", this::nop).addShortAlias("test", "t")
+                .parseOptions(Arrays.asList("-s")));
+        assertEquals("test: unrecognized option '-s'", e.getMessage());
     }
 
     @Test
     public void testParserRejectsWrongLongopt() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: unrecognized option '--wrong'");
-        new OptionParser("test").addFlagParameter("test", this::nop).parseOptions(Arrays.asList("--wrong"));
+        Exception e = assertThrows(OptionParseException.class, () -> new OptionParser("test").addFlagParameter("test", this::nop).parseOptions(Arrays.asList("--wrong")));
+        assertEquals("test: unrecognized option '--wrong'", e.getMessage());
     }
 
     @Test
@@ -80,87 +70,79 @@
 
     @Test
     public void testParserOptionFailsIfMissing() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: unrecognized option '--test2'");
         AtomicReference<String> argFound = new AtomicReference<>();
         OptionParser parser = new OptionParser("test")
                 .addArgumentParameter("test", OptionCount.REQUIRED, argFound::set);
 
-        parser.parseOptions(Arrays.asList("--test2", "arg"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("--test2", "arg")));
+        assertEquals("test: unrecognized option '--test2'", e.getMessage());
     }
 
     @Test
     public void testParserOptionFailsIfMissingArgument() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: unrecognized option '--test2'");
         AtomicReference<String> argFound = new AtomicReference<>();
         OptionParser parser = new OptionParser("test")
                 .addArgumentParameter("test", OptionCount.REQUIRED, argFound::set);
 
-        parser.parseOptions(Arrays.asList("--test2", "--other"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("--test2", "--other")));
+        assertEquals("test: unrecognized option '--test2'", e.getMessage());
     }
 
     @Test
     public void testParserOptionFailsIfMissing2() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: option '--test' is required");
         AtomicReference<String> argFound = new AtomicReference<>();
         OptionParser parser = new OptionParser("test")
                 .addArgumentParameter("test", OptionCount.REQUIRED, argFound::set);
 
-        parser.parseOptions(Arrays.asList("--", "--test", "arg"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("--", "--test", "arg")));
+        assertEquals("test: option '--test' is required", e.getMessage());
     }
 
     @Test
     public void testParserOptionFailsIfTwice() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: option '--test' may not appear multiple times");
         AtomicReference<String> argFound = new AtomicReference<>();
         OptionParser parser = new OptionParser("test")
                 .addArgumentParameter("test", OptionCount.REQUIRED, argFound::set);
 
-        parser.parseOptions(Arrays.asList("--test", "arg", "--test", "arg"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("--test", "arg", "--test", "arg")));
+        assertEquals("test: option '--test' may not appear multiple times", e.getMessage());
     }
 
     @Test
     public void testParserOptionFailsIfTwiceForAlias() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: option '-t' may not appear multiple times");
         AtomicReference<String> argFound = new AtomicReference<>();
         OptionParser parser = new OptionParser("test")
                 .addArgumentParameter("test", OptionCount.REQUIRED, argFound::set)
                 .addShortAlias("test", "t");
 
-        parser.parseOptions(Arrays.asList("--test", "arg", "-t", "arg"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("--test", "arg", "-t", "arg")));
+        assertEquals("test: option '-t' may not appear multiple times", e.getMessage());
     }
 
     @Test
     public void testOptionalOptionFailsIfTwice() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: option '--test' may not appear multiple times");
         OptionParser parser = new OptionParser("test")
                 .addFlagParameter("test", this::nop);
-        parser.parseOptions(Arrays.asList("--test", "--test"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("--test", "--test")));
+        assertEquals("test: option '--test' may not appear multiple times", e.getMessage());
     }
 
     @Test
     public void testOptionalOptionFailsIfTwiceForAlias() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: option '-t' may not appear multiple times");
         OptionParser parser = new OptionParser("test")
                 .addFlagParameter("test", this::nop)
                 .addShortAlias("test", "t");
-        parser.parseOptions(Arrays.asList("-t", "-t"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("-t", "-t")));
+        assertEquals("test: option '-t' may not appear multiple times", e.getMessage());
     }
 
     @Test
     public void testOptionalOptionFailsIfTwiceForAlias2() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: option '-t' may not appear multiple times");
         OptionParser parser = new OptionParser("test")
                 .addFlagParameter("test", this::nop)
                 .addShortAlias("test", "t");
-        parser.parseOptions(Arrays.asList("-tt"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("-tt")));
+        assertEquals("test: option '-t' may not appear multiple times", e.getMessage());
     }
 
     @Test
@@ -187,65 +169,59 @@
 
     @Test
     public void testLongArgumentsMissingOption() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: option '--test' requires an argument");
         OptionParser parser = new OptionParser("test")
                 .addArgumentParameter("test", OptionCount.REQUIRED, this::nop);
 
-        parser.parseOptions(Arrays.asList("--test"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("--test")));
+        assertEquals("test: option '--test' requires an argument", e.getMessage());
     }
 
     @Test
     public void testLongArgumentsMissingOption2() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: option '--test' requires an argument");
         OptionParser parser = new OptionParser("test")
                 .addArgumentParameter("test", OptionCount.REQUIRED, this::nop);
 
-        parser.parseOptions(Arrays.asList("--test", "--", "x"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("--test", "--", "x")));
+        assertEquals("test: option '--test' requires an argument", e.getMessage());
     }
 
     @Test
     public void testShortArgumentsMissingOption() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: option '-t' requires an argument");
         OptionParser parser = new OptionParser("test")
                 .addArgumentParameter("test", OptionCount.REQUIRED, this::nop)
                 .addShortAlias("test", "t");
 
-        parser.parseOptions(Arrays.asList("-t"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("-t")));
+        assertEquals("test: option '-t' requires an argument", e.getMessage());
     }
 
     @Test
     public void testShortArgumentsMissingOption2() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: option '-t' requires an argument");
         OptionParser parser = new OptionParser("test")
                 .addArgumentParameter("test", OptionCount.REQUIRED, this::nop)
                 .addShortAlias("test", "t");
 
-        parser.parseOptions(Arrays.asList("-t", "--", "x"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("-t", "--", "x")));
+        assertEquals("test: option '-t' requires an argument", e.getMessage());
     }
 
     @Test
     public void testLongFlagHasOption() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: option '--test' does not allow an argument");
         OptionParser parser = new OptionParser("test")
                 .addFlagParameter("test", this::nop);
 
-        parser.parseOptions(Arrays.asList("--test=arg"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("--test=arg")));
+        assertEquals("test: option '--test' does not allow an argument", e.getMessage());
     }
 
     @Test
     public void testShortFlagHasOption() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: option '-t' does not allow an argument");
         OptionParser parser = new OptionParser("test")
                 .addFlagParameter("test", this::nop)
                 .addShortAlias("test", "t");
 
-        parser.parseOptions(Arrays.asList("-t=arg"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("-t=arg")));
+        assertEquals("test: option '-t' does not allow an argument", e.getMessage());
     }
 
     @Test
@@ -305,8 +281,6 @@
 
     @Test
     public void testAmbiguousAlternatives() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: option '--fl' is ambiguous");
         AtomicReference<String> argFound = new AtomicReference<>();
         AtomicBoolean usedFlag = new AtomicBoolean();
         AtomicBoolean unusedFlag = new AtomicBoolean();
@@ -316,13 +290,15 @@
                 .addFlagParameter("flag", () -> usedFlag.set(true))
                 .addFlagParameter("fleg", () -> unusedFlag.set(true));
 
-        parser.parseOptions(Arrays.asList("--te=arg", "--fl"));
+        Exception e = assertThrows(OptionParseException.class, () -> parser.parseOptions(Arrays.asList("--te=arg", "--fl")));
+        assertEquals("test: option '--fl' is ambiguous", e.getMessage());
     }
 
     @Test
     public void testMultipleShort() {
-        thrown.expect(OptionParseException.class);
-        thrown.expectMessage("test: unrecognized option '-ft'");
+        // TODO figure out what is supposed to happen here
+        // thrown.expect(OptionParseException.class);
+        // thrown.expectMessage("test: unrecognized option '-ft'");
         AtomicReference<String> argFound = new AtomicReference<>();
         AtomicBoolean usedFlag = new AtomicBoolean();
         AtomicBoolean unusedFlag = new AtomicBoolean();
@@ -334,14 +310,22 @@
                 .addShortAlias("flag", "f")
                 .addFlagParameter("fleg", () -> unusedFlag.set(true));
 
-        List<String> remaining = parser.parseOptions(Arrays.asList("-ft=arg", "x"));
+        final List<String> remaining = new ArrayList<>();
+        Exception e = assertThrows(OptionParseException.class, () -> remaining.addAll(parser.parseOptions(Arrays.asList("-ft=arg", "x"))));
+        assertEquals("test: unrecognized option '-ft'", e.getMessage());
 
+        /*
+         * Since we are receiving an exception, this is probably empty.
+         * In the original code, none of the following asserts were actually used.
+         * Therefore, this test is now failing.
+         */
         assertEquals(Arrays.asList("x"), remaining);
         assertEquals("arg", argFound.get());
         assertTrue(usedFlag.get());
         assertFalse(unusedFlag.get());
 
-        remaining = parser.parseOptions(Arrays.asList("-ft", "arg", "x"));
+        remaining.clear();
+        remaining.addAll(parser.parseOptions(Arrays.asList("-ft", "arg", "x")));
 
         assertEquals(Arrays.asList("x"), remaining);
         assertEquals("arg", argFound.get());
@@ -348,7 +332,8 @@
         assertTrue(usedFlag.get());
         assertFalse(unusedFlag.get());
 
-        remaining = parser.parseOptions(Arrays.asList("-f", "-t=arg", "x"));
+        remaining.clear();
+        remaining.addAll(parser.parseOptions(Arrays.asList("-f", "-t=arg", "x")));
 
         assertEquals(Arrays.asList("x"), remaining);
         assertEquals("arg", argFound.get());
@@ -358,84 +343,73 @@
 
     @Test
     public void testIllegalOptionName() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("Illegal option name: ''");
-        new OptionParser("test").addFlagParameter("", this::nop);
+        Exception e = assertThrows(IllegalArgumentException.class, () -> new OptionParser("test").addFlagParameter("", this::nop));
+        assertEquals("Illegal option name: ''", e.getMessage());
     }
 
     @Test
     public void testIllegalOptionName2() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("Illegal option name: '-'");
-        new OptionParser("test").addFlagParameter("-", this::nop);
+        Exception e = assertThrows(IllegalArgumentException.class, () -> new OptionParser("test").addFlagParameter("-", this::nop));
+        assertEquals("Illegal option name: '-'", e.getMessage());
     }
 
     @Test
     public void testIllegalOptionName3() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("Illegal option name: '-test'");
-        new OptionParser("test").addFlagParameter("-test", this::nop);
+        Exception e = assertThrows(IllegalArgumentException.class, () -> new OptionParser("test").addFlagParameter("-test", this::nop));
+        assertEquals("Illegal option name: '-test'", e.getMessage());
     }
 
     @Test
     public void testIllegalOptionName4() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("Illegal option name: '$'");
-        new OptionParser("test").addFlagParameter("$", this::nop);
+        Exception e = assertThrows(IllegalArgumentException.class, () -> new OptionParser("test").addFlagParameter("$", this::nop));
+        assertEquals("Illegal option name: '$'", e.getMessage());
     }
 
     @Test
     public void testDuplicateOptionName() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("The option '--test' is already registered");
-        new OptionParser("test").addFlagParameter("test", this::nop).addFlagParameter("test", this::nop);
+        Exception e = assertThrows(IllegalArgumentException.class, () -> new OptionParser("test").addFlagParameter("test", this::nop).addFlagParameter("test", this::nop));
+        assertEquals("The option '--test' is already registered", e.getMessage());
     }
 
     @Test
     public void testDuplicateOptionName2() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("The option '--test' is already registered");
-        new OptionParser("test").addFlagParameter("test", this::nop)
-            .addArgumentParameter("test", OptionCount.OPTIONAL, this::nop);
+        Exception e = assertThrows(IllegalArgumentException.class, () -> new OptionParser("test").addFlagParameter("test", this::nop)
+            .addArgumentParameter("test", OptionCount.OPTIONAL, this::nop));
+        assertEquals("The option '--test' is already registered", e.getMessage());
     }
 
     @Test
     public void testInvalidShortAlias() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("Short name '$' must be one character");
-        new OptionParser("test").addFlagParameter("test", this::nop).addShortAlias("test", "$");
+        Exception e = assertThrows(IllegalArgumentException.class, () -> new OptionParser("test").addFlagParameter("test", this::nop).addShortAlias("test", "$"));
+        assertEquals("Short name '$' must be one character", e.getMessage());
     }
 
     @Test
     public void testInvalidShortAlias2() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("Short name '' must be one character");
-        new OptionParser("test").addFlagParameter("test", this::nop).addShortAlias("test", "");
+        Exception e = assertThrows(IllegalArgumentException.class, () -> new OptionParser("test").addFlagParameter("test", this::nop).addShortAlias("test", ""));
+        assertEquals("Short name '' must be one character", e.getMessage());
     }
 
     @Test
     public void testInvalidShortAlias3() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("Short name 'xx' must be one character");
-        new OptionParser("test").addFlagParameter("test", this::nop).addShortAlias("test", "xx");
+        Exception e = assertThrows(IllegalArgumentException.class, () -> new OptionParser("test").addFlagParameter("test", this::nop).addShortAlias("test", "xx"));
+        assertEquals("Short name 'xx' must be one character", e.getMessage());
     }
 
     @Test
     public void testDuplicateShortAlias() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("Short name 't' is already used");
-        new OptionParser("test").addFlagParameter("test", this::nop)
+        Exception e = assertThrows(IllegalArgumentException.class, () -> new OptionParser("test").addFlagParameter("test", this::nop)
         .addFlagParameter("test2", this::nop)
         .addShortAlias("test", "t")
-        .addShortAlias("test2", "t");
+        .addShortAlias("test2", "t"));
+        assertEquals("Short name 't' is already used", e.getMessage());
     }
 
     @Test
     public void testInvalidShortNoLong() {
-        thrown.expect(IllegalArgumentException.class);
-        thrown.expectMessage("No long definition for test2 was defined. " +
-                "Define the long definition first before creating a short definition for it.");
-        new OptionParser("test").addFlagParameter("test", this::nop).addShortAlias("test2", "t");
+        Exception e = assertThrows(IllegalArgumentException.class, () -> new OptionParser("test").addFlagParameter("test", this::nop).addShortAlias("test2", "t"));
+        assertEquals("No long definition for test2 was defined. " +
+                "Define the long definition first before creating a short definition for it.", e.getMessage());
     }
 
     private void nop() {
Index: test/unit/org/openstreetmap/josm/tools/StringParserTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/tools/StringParserTest.java	(revision 16603)
+++ test/unit/org/openstreetmap/josm/tools/StringParserTest.java	(working copy)
@@ -2,15 +2,16 @@
 package org.openstreetmap.josm.tools;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 
 import java.util.Optional;
 
-import net.trajano.commons.testing.UtilityClassTestUtil;
 import org.junit.Test;
 
+import net.trajano.commons.testing.UtilityClassTestUtil;
+
 /**
  * Unit tests of {@link StringParser} class.
  */
