diff --git a/ivy.xml b/ivy.xml
index d6fa0b3232..30a8d98a4b 100644
--- a/ivy.xml
+++ b/ivy.xml
@@ -60,6 +60,7 @@
         <dependency conf="test->default" org="com.github.tomakehurst" name="wiremock" rev="2.27.2"/>
         <dependency conf="test->default" org="io.github.classgraph" name="classgraph" rev="4.8.110"/>
         <dependency conf="test->default" org="org.junit.platform" name="junit-platform-launcher" rev="1.7.2"/>
+        <dependency conf="test->default" org="org.junit.platform" name="junit-platform-suite-api" rev="1.7.2"/>
         <dependency conf="test->default" org="org.junit.vintage" name="junit-vintage-engine" rev="5.7.2"/>
         <dependency conf="test->default" org="org.junit.jupiter" name="junit-jupiter-params" rev="5.7.2"/>
         <dependency conf="test->default" org="org.junit.jupiter" name="junit-jupiter-api" rev="5.7.2"/>
diff --git a/test/functional/org/openstreetmap/josm/data/BoundariesTestIT.java b/test/functional/org/openstreetmap/josm/data/BoundariesTestIT.java
index d4734744a8..c3ffd340e0 100644
--- a/test/functional/org/openstreetmap/josm/data/BoundariesTestIT.java
+++ b/test/functional/org/openstreetmap/josm/data/BoundariesTestIT.java
@@ -19,10 +19,12 @@ import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.IntegrationTest;
 
 /**
  * Test of boundaries OSM file.
  */
+@IntegrationTest
 class BoundariesTestIT {
 
     private static final List<String> RETIRED_ISO3166_1_CODES = Arrays.asList(
diff --git a/test/functional/org/openstreetmap/josm/data/imagery/ImageryCompareTestIT.java b/test/functional/org/openstreetmap/josm/data/imagery/ImageryCompareTestIT.java
index 60ca4fbcee..ea2467d52e 100644
--- a/test/functional/org/openstreetmap/josm/data/imagery/ImageryCompareTestIT.java
+++ b/test/functional/org/openstreetmap/josm/data/imagery/ImageryCompareTestIT.java
@@ -6,29 +6,26 @@ import static org.junit.jupiter.api.Assertions.fail;
 import java.net.URL;
 
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junit.jupiter.api.Timeout;
 import org.openstreetmap.josm.spi.preferences.Config;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.HTTP;
+import org.openstreetmap.josm.testutils.annotations.IntegrationTest;
 import org.openstreetmap.josm.tools.HttpClient;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
 /**
  * Automatic test of imagery synchronization between JOSM and ELI.
  * See <a href="https://josm.openstreetmap.de/wiki/ImageryCompare">JOSM wiki</a>
  */
+@IntegrationTest
+@Timeout(20)
+@HTTP
+@BasicPreferences
 class ImageryCompareTestIT {
 
     private static final String BLACK_PREFIX = "<pre style=\"margin:3px;color:black\">";
     private static final String RED_PREFIX = "<pre style=\"margin:3px;color:red\">";
 
-    /**
-     * Setup test.
-     */
-    @RegisterExtension
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().timeout(60000);
-
     /**
      * Test of imagery entries.
      * @throws Exception if an error occurs
diff --git a/test/functional/org/openstreetmap/josm/data/osm/TaginfoTestIT.java b/test/functional/org/openstreetmap/josm/data/osm/TaginfoTestIT.java
index d153334831..2c97e062dd 100644
--- a/test/functional/org/openstreetmap/josm/data/osm/TaginfoTestIT.java
+++ b/test/functional/org/openstreetmap/josm/data/osm/TaginfoTestIT.java
@@ -15,30 +15,26 @@ import javax.json.JsonReader;
 import javax.json.JsonValue;
 
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
+import org.junit.jupiter.api.Timeout;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker;
 import org.openstreetmap.josm.data.validation.tests.TagChecker;
 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.ParseException;
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresets;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.HTTP;
+import org.openstreetmap.josm.testutils.annotations.IntegrationTest;
 import org.openstreetmap.josm.tools.HttpClient;
 import org.xml.sax.SAXException;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
 /**
  * Various integration tests with Taginfo.
  */
+@Timeout(value = 20)
+@BasicPreferences
+@HTTP
+@IntegrationTest
 class TaginfoTestIT {
-
-    /**
-     * Setup test.
-     */
-    @RegisterExtension
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().timeout(20000);
-
     /**
      * Checks that popular tags are known (i.e included in internal presets, or deprecated, or explicitely ignored)
      * @throws SAXException if any XML parsing error occurs
diff --git a/test/functional/org/openstreetmap/josm/gui/GettingStartedTest.java b/test/functional/org/openstreetmap/josm/gui/GettingStartedTest.java
index 6c7a9ed0db..ddf273d32e 100644
--- a/test/functional/org/openstreetmap/josm/gui/GettingStartedTest.java
+++ b/test/functional/org/openstreetmap/josm/gui/GettingStartedTest.java
@@ -5,24 +5,18 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals;
 
 import java.io.IOException;
 
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Disabled;
-import org.openstreetmap.josm.JOSMFixture;
+import org.junit.jupiter.api.Test;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.HTTP;
 
 /**
  * Tests the {@link GettingStarted} class.
  */
+@BasicPreferences
+@HTTP
 class GettingStartedTest {
 
-    /**
-     * Setup test.
-     */
-    @BeforeAll
-    public static void init() {
-        JOSMFixture.createFunctionalTestFixture().init();
-    }
-
     /**
      * Tests that image links are replaced.
      *
diff --git a/test/functional/org/openstreetmap/josm/gui/mappaint/MapCSSRendererTest.java b/test/functional/org/openstreetmap/josm/gui/mappaint/MapCSSRendererTest.java
index 97afd4d5b9..da4507b0be 100644
--- a/test/functional/org/openstreetmap/josm/gui/mappaint/MapCSSRendererTest.java
+++ b/test/functional/org/openstreetmap/josm/gui/mappaint/MapCSSRendererTest.java
@@ -64,7 +64,7 @@ public class MapCSSRendererTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().projection();
+    public JOSMTestRules test = new JOSMTestRules().projection();
 
     // development flag - set to true in order to update all reference images
     private static final boolean UPDATE_ALL = false;
diff --git a/test/functional/org/openstreetmap/josm/gui/mappaint/StyleCacheTest.java b/test/functional/org/openstreetmap/josm/gui/mappaint/StyleCacheTest.java
index 6bd117d1dc..59dc91df17 100644
--- a/test/functional/org/openstreetmap/josm/gui/mappaint/StyleCacheTest.java
+++ b/test/functional/org/openstreetmap/josm/gui/mappaint/StyleCacheTest.java
@@ -28,6 +28,7 @@ import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.io.Compression;
 import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.Pair;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -35,6 +36,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Test {@link StyleCache}.
  */
+@BasicPreferences
 class StyleCacheTest {
 
     private static final int IMG_WIDTH = 1400;
@@ -51,7 +53,7 @@ class StyleCacheTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().main().preferences().projection().mapStyles().timeout(60000);
+    public JOSMTestRules test = new JOSMTestRules().main().projection().mapStyles().timeout(60000);
 
     /**
      * Load the test data that is required.
diff --git a/test/functional/org/openstreetmap/josm/io/MultiFetchServerObjectReaderTest.java b/test/functional/org/openstreetmap/josm/io/MultiFetchServerObjectReaderTest.java
index f5ac350e3d..f8f9045f95 100644
--- a/test/functional/org/openstreetmap/josm/io/MultiFetchServerObjectReaderTest.java
+++ b/test/functional/org/openstreetmap/josm/io/MultiFetchServerObjectReaderTest.java
@@ -29,8 +29,6 @@ import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Timeout;
-import org.junit.jupiter.api.extension.RegisterExtension;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.Changeset;
@@ -43,7 +41,9 @@ import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.spi.preferences.Config;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.Main;
+import org.openstreetmap.josm.testutils.annotations.OsmApiType;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
@@ -52,16 +52,12 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  */
 @SuppressFBWarnings(value = "CRLF_INJECTION_LOGS")
 @Timeout(value = 60, unit = TimeUnit.SECONDS)
+@BasicPreferences
+@OsmApiType(OsmApiType.APIType.DEV)
+@Main
 class MultiFetchServerObjectReaderTest {
     private static final Logger logger = Logger.getLogger(MultiFetchServerObjectReader.class.getName());
 
-    /**
-     * Setup test.
-     */
-    @RegisterExtension
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences();
-
     /**
      * builds a large data set to be used later for testing MULTI FETCH on the server
      *
@@ -163,7 +159,6 @@ class MultiFetchServerObjectReaderTest {
             return;
         }
         logger.info("initializing ...");
-        JOSMFixture.createFunctionalTestFixture().init();
 
         Config.getPref().put("osm-server.auth-method", "basic");
 
diff --git a/test/functional/org/openstreetmap/josm/io/OsmServerBackreferenceReaderTest.java b/test/functional/org/openstreetmap/josm/io/OsmServerBackreferenceReaderTest.java
index 15cca85efe..39227ad8e3 100644
--- a/test/functional/org/openstreetmap/josm/io/OsmServerBackreferenceReaderTest.java
+++ b/test/functional/org/openstreetmap/josm/io/OsmServerBackreferenceReaderTest.java
@@ -25,7 +25,6 @@ import java.util.logging.Logger;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.APIDataSet;
 import org.openstreetmap.josm.data.coor.LatLon;
@@ -42,6 +41,8 @@ import org.openstreetmap.josm.data.projection.ProjectionRegistry;
 import org.openstreetmap.josm.data.projection.Projections;
 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.testutils.annotations.FullPreferences;
+import org.openstreetmap.josm.testutils.annotations.OsmApiType;
 import org.openstreetmap.josm.tools.Logging;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -51,6 +52,8 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  * @since 1806
  */
 @SuppressFBWarnings(value = "CRLF_INJECTION_LOGS")
+@FullPreferences
+@OsmApiType(OsmApiType.APIType.DEV)
 class OsmServerBackreferenceReaderTest {
     private static final Logger logger = Logger.getLogger(OsmServerBackreferenceReader.class.getName());
 
@@ -165,8 +168,6 @@ class OsmServerBackreferenceReaderTest {
         }
         logger.info("initializing ...");
 
-        JOSMFixture.createFunctionalTestFixture().init();
-
         Config.getPref().put("osm-server.auth-method", "basic");
 
         // don't use atomic upload, the test API server can't cope with large diff uploads
diff --git a/test/functional/org/openstreetmap/josm/tools/ImageProviderTestIT.java b/test/functional/org/openstreetmap/josm/tools/ImageProviderTestIT.java
index 16be1d91c9..9904953772 100644
--- a/test/functional/org/openstreetmap/josm/tools/ImageProviderTestIT.java
+++ b/test/functional/org/openstreetmap/josm/tools/ImageProviderTestIT.java
@@ -8,10 +8,12 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.IntegrationTest;
 
 /**
  * Integration tests of {@link ImageProvider} class.
  */
+@IntegrationTest
 class ImageProviderTestIT {
 
     /**
diff --git a/test/performance/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRendererPerformanceTestParent.java b/test/performance/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRendererPerformanceTestParent.java
index fe040014b8..5cb6a2bdb8 100644
--- a/test/performance/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRendererPerformanceTestParent.java
+++ b/test/performance/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRendererPerformanceTestParent.java
@@ -26,11 +26,13 @@ import org.openstreetmap.josm.io.Compression;
 import org.openstreetmap.josm.io.OsmReader;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Abstract superclass of {@code StyledMapRendererPerformanceTest} and {@code WireframeMapRendererPerformanceTest}.
  */
-@Timeout(value = 15*60, unit = TimeUnit.SECONDS)
+@Timeout(value = 15, unit = TimeUnit.MINUTES)
+@BasicPreferences
 abstract class AbstractMapRendererPerformanceTestParent {
 
     private static final int IMG_WIDTH = 1400;
diff --git a/test/performance/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRendererPerformanceTest.java b/test/performance/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRendererPerformanceTest.java
index ded650f02e..f95fc24e6f 100644
--- a/test/performance/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRendererPerformanceTest.java
+++ b/test/performance/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRendererPerformanceTest.java
@@ -11,10 +11,12 @@ import org.junit.jupiter.api.BeforeAll;
 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.FullPreferences;
 
 /**
  * Performance test of {@code StyledMapRenderer}.
  */
+@FullPreferences
 class StyledMapRendererPerformanceTest extends AbstractMapRendererPerformanceTestParent {
 
     @BeforeAll
diff --git a/test/performance/org/openstreetmap/josm/data/validation/ValidationTaskPerformanceTest.java b/test/performance/org/openstreetmap/josm/data/validation/ValidationTaskPerformanceTest.java
index 25d9295d12..d4311a6ba0 100644
--- a/test/performance/org/openstreetmap/josm/data/validation/ValidationTaskPerformanceTest.java
+++ b/test/performance/org/openstreetmap/josm/data/validation/ValidationTaskPerformanceTest.java
@@ -1,6 +1,12 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.data.validation;
 
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -13,16 +19,12 @@ import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Performance test of {@code ValidationTask}.
  */
+@BasicPreferences
 class ValidationTaskPerformanceTest {
 
     private List<org.openstreetmap.josm.data.validation.Test> tests;
@@ -32,7 +34,7 @@ class ValidationTaskPerformanceTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().projection().territories().preferences();
+    public JOSMTestRules test = new JOSMTestRules().projection().territories();
 
     /**
      * Setup test.
diff --git a/test/performance/org/openstreetmap/josm/gui/mappaint/MapRendererPerformanceTest.java b/test/performance/org/openstreetmap/josm/gui/mappaint/MapRendererPerformanceTest.java
index 430740e618..2171d88aa3 100644
--- a/test/performance/org/openstreetmap/josm/gui/mappaint/MapRendererPerformanceTest.java
+++ b/test/performance/org/openstreetmap/josm/gui/mappaint/MapRendererPerformanceTest.java
@@ -16,16 +16,18 @@ import java.util.EnumMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 import javax.imageio.ImageIO;
 
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import org.junit.Assert;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
 import org.junit.jupiter.api.extension.RegisterExtension;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.PerformanceTestUtils;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.Bounds;
@@ -43,12 +45,13 @@ import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
 import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
 import org.openstreetmap.josm.gui.mappaint.styleelement.StyleElement;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Performance test of map renderer.
  */
+@Timeout(value = 15, unit = TimeUnit.MINUTES)
+@BasicPreferences
 public class MapRendererPerformanceTest {
 
     private static final boolean DUMP_IMAGE = false; // dump images to file for debugging purpose
@@ -84,7 +87,7 @@ public class MapRendererPerformanceTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules josmTestRules = new JOSMTestRules().main().projection().preferences().timeout(15 * 60 * 1000);
+    public JOSMTestRules josmTestRules = new JOSMTestRules().main().projection();
 
     /**
      * Initializes test environment.
@@ -92,8 +95,6 @@ public class MapRendererPerformanceTest {
      */
     @BeforeAll
     public static void load() throws Exception {
-        JOSMFixture.createPerformanceTestFixture().init(true);
-
         img = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_ARGB);
         g = (Graphics2D) img.getGraphics();
         g.setClip(0, 0, IMG_WIDTH, IMG_HEIGHT);
diff --git a/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSPerformanceTest.java b/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSPerformanceTest.java
index 504daea82d..1b79dc4de3 100644
--- a/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSPerformanceTest.java
+++ b/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSPerformanceTest.java
@@ -10,8 +10,6 @@ import java.io.IOException;
 import java.util.Collection;
 
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.BeforeAll;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.PerformanceTestUtils;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -21,12 +19,14 @@ import org.openstreetmap.josm.data.preferences.sources.SourceType;
 import org.openstreetmap.josm.gui.NavigatableComponent;
 import org.openstreetmap.josm.gui.mappaint.MapRendererPerformanceTest;
 import org.openstreetmap.josm.io.IllegalDataException;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * This performance test measures the time for a full run of MapPaintVisitor.visitAll()
  * against a test data set using a test style.
  *
  */
+@BasicPreferences
 class MapCSSPerformanceTest {
 
     /* ------------------------ configuration section  ---------------------------- */
@@ -47,14 +47,6 @@ class MapCSSPerformanceTest {
           }
     }
 
-    /**
-     * Setup test.
-     */
-    @BeforeAll
-    public static void createJOSMFixture() {
-        JOSMFixture.createPerformanceTestFixture().init(true);
-    }
-
     long timed(Runnable callable) {
         long before = System.currentTimeMillis();
         callable.run();
diff --git a/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSourceFilterTest.java b/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSourceFilterTest.java
index 21241668dd..073d720f06 100644
--- a/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSourceFilterTest.java
+++ b/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSourceFilterTest.java
@@ -3,21 +3,21 @@ package org.openstreetmap.josm.gui.mappaint.mapcss;
 
 import java.util.concurrent.TimeUnit;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Timeout;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.PerformanceTestUtils;
 import org.openstreetmap.josm.PerformanceTestUtils.PerformanceTestTimer;
 import org.openstreetmap.josm.data.osm.OsmDataGenerator;
 import org.openstreetmap.josm.data.osm.OsmDataGenerator.KeyValueDataGenerator;
 import org.openstreetmap.josm.gui.mappaint.MultiCascade;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Tests how fast {@link MapCSSStyleSource} finds the right style candidates for one object.
  * @author Michael Zangl
  */
-@Timeout(value = 15*60, unit = TimeUnit.SECONDS)
+@Timeout(value = 15, unit = TimeUnit.MINUTES)
+@BasicPreferences
 class MapCSSStyleSourceFilterTest {
 
     private static final int TEST_RULE_COUNT = 10000;
@@ -80,14 +80,6 @@ class MapCSSStyleSourceFilterTest {
 
     private static final int APPLY_CALLS = 100000;
 
-    /**
-     * Prepare the test.
-     */
-    @BeforeAll
-    public static void createJOSMFixture() {
-        JOSMFixture.createPerformanceTestFixture().init(true);
-    }
-
     /**
      * Time how long it takes to evaluate [key=value] rules
      */
diff --git a/test/performance/org/openstreetmap/josm/io/OsmReaderPerformanceTest.java b/test/performance/org/openstreetmap/josm/io/OsmReaderPerformanceTest.java
index e9a1a1c78f..542c88f275 100644
--- a/test/performance/org/openstreetmap/josm/io/OsmReaderPerformanceTest.java
+++ b/test/performance/org/openstreetmap/josm/io/OsmReaderPerformanceTest.java
@@ -11,13 +11,12 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.concurrent.TimeUnit;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Timeout;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.PerformanceTestUtils;
 import org.openstreetmap.josm.PerformanceTestUtils.PerformanceTestTimer;
 import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * This test tests how fast we are at reading an OSM file.
@@ -26,18 +25,11 @@ import org.openstreetmap.josm.data.osm.DataSet;
  *
  * @author Michael Zangl
  */
-@Timeout(value = 15*60, unit = TimeUnit.SECONDS)
+@Timeout(value = 15, unit = TimeUnit.MINUTES)
+@BasicPreferences
 class OsmReaderPerformanceTest {
     private static final int TIMES = 4;
 
-    /**
-     * Prepare the test.
-     */
-    @BeforeAll
-    public static void createJOSMFixture() {
-        JOSMFixture.createPerformanceTestFixture().init(true);
-    }
-
     /**
      * Simulates a plain read of a .osm.bz2 file (from memory)
      * @throws Exception if an error occurs
diff --git a/test/performance/org/openstreetmap/josm/io/OsmWriterPerformanceTest.java b/test/performance/org/openstreetmap/josm/io/OsmWriterPerformanceTest.java
index 8835650fe8..975a7a416e 100644
--- a/test/performance/org/openstreetmap/josm/io/OsmWriterPerformanceTest.java
+++ b/test/performance/org/openstreetmap/josm/io/OsmWriterPerformanceTest.java
@@ -1,37 +1,29 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.io;
 
-import org.junit.jupiter.api.BeforeAll;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.concurrent.TimeUnit;
+
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Timeout;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.PerformanceTestUtils;
 import org.openstreetmap.josm.PerformanceTestUtils.PerformanceTestTimer;
 import org.openstreetmap.josm.data.osm.DataSet;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.concurrent.TimeUnit;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * This test tests how fast we are at writing an OSM file.
  * <p>
  * For this, we use the neubrandenburg-file, which is a good real world example of an OSM file.
  */
-@Timeout(value = 15*60, unit = TimeUnit.SECONDS)
+@Timeout(value = 15, unit = TimeUnit.MINUTES)
+@BasicPreferences
 class OsmWriterPerformanceTest {
     private static final int TIMES = 4;
     private DataSet neubrandenburgDataSet;
 
-    /**
-     * Prepare the test.
-     */
-    @BeforeAll
-    public static void createJOSMFixture() {
-        JOSMFixture.createPerformanceTestFixture().init(true);
-    }
-
     /**
      * Setup test
      * @throws Exception if an error occurs
diff --git a/test/unit/org/openstreetmap/josm/TestUtils.java b/test/unit/org/openstreetmap/josm/TestUtils.java
index c30e05388d..266ebe22f8 100644
--- a/test/unit/org/openstreetmap/josm/TestUtils.java
+++ b/test/unit/org/openstreetmap/josm/TestUtils.java
@@ -16,6 +16,8 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.net.Authenticator;
+import java.net.PasswordAuthentication;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.time.Instant;
@@ -53,17 +55,20 @@ import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.gui.progress.ProgressTaskId;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.io.Compression;
+import org.openstreetmap.josm.io.OsmApi;
+import org.openstreetmap.josm.io.auth.CredentialsAgentException;
+import org.openstreetmap.josm.io.auth.JosmPreferencesCredentialAgent;
 import org.openstreetmap.josm.testutils.FakeGraphics;
 import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
 import org.openstreetmap.josm.testutils.mockers.WindowMocker;
 import org.openstreetmap.josm.tools.JosmRuntimeException;
+import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.ReflectionUtils;
 import org.openstreetmap.josm.tools.Utils;
 import org.openstreetmap.josm.tools.WikiReader;
 
 import com.github.tomakehurst.wiremock.WireMockServer;
 import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
-
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import io.github.classgraph.ClassGraph;
 import io.github.classgraph.ClassInfoList;
@@ -646,7 +651,18 @@ public final class TestUtils {
      * @return {@code true} if {@code osm.username} and {@code osm.password} have been defined on the command line
      */
     public static boolean areCredentialsProvided() {
-        return Utils.getSystemProperty("osm.username") != null && Utils.getSystemProperty("osm.password") != null;
+        final String username = Utils.getSystemProperty("osm.username");
+        final String password = Utils.getSystemProperty("osm.password");
+        if (username != null && password != null) {
+            try {
+                new JosmPreferencesCredentialAgent().store(Authenticator.RequestorType.SERVER,
+                        OsmApi.getOsmApi().getHost(), new PasswordAuthentication(username, password.toCharArray()));
+                return true;
+            } catch (CredentialsAgentException e) {
+                Logging.error("Credentials could not be stored");
+            }
+        }
+        return false;
     }
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/actions/AboutActionTest.java b/test/unit/org/openstreetmap/josm/actions/AboutActionTest.java
index 51a4535692..dd6da352e1 100644
--- a/test/unit/org/openstreetmap/josm/actions/AboutActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/AboutActionTest.java
@@ -8,10 +8,12 @@ import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link AboutAction}.
  */
+@BasicPreferences
 final class AboutActionTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/actions/AlignInLineActionTest.java b/test/unit/org/openstreetmap/josm/actions/AlignInLineActionTest.java
index 77f2149805..b907ca891a 100644
--- a/test/unit/org/openstreetmap/josm/actions/AlignInLineActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/AlignInLineActionTest.java
@@ -18,12 +18,14 @@ import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests for class {@link AlignInLineAction}.
  */
+@BasicPreferences
 final class AlignInLineActionTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/actions/CreateMultipolygonActionTest.java b/test/unit/org/openstreetmap/josm/actions/CreateMultipolygonActionTest.java
index 495fec7007..03b3b516a5 100644
--- a/test/unit/org/openstreetmap/josm/actions/CreateMultipolygonActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/CreateMultipolygonActionTest.java
@@ -30,6 +30,9 @@ import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.HTTP;
+import org.openstreetmap.josm.testutils.annotations.Territories;
 import org.openstreetmap.josm.tools.Pair;
 import org.openstreetmap.josm.tools.SubclassFilteredCollection;
 
@@ -38,6 +41,9 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit test of {@link CreateMultipolygonAction}
  */
+@BasicPreferences
+@HTTP
+@Territories(Territories.Initialize.ALL)
 class CreateMultipolygonActionTest {
 
     /**
@@ -45,7 +51,7 @@ class CreateMultipolygonActionTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().projection().main().preferences().mapStyles();
+    public JOSMTestRules test = new JOSMTestRules().projection().main().mapStyles();
 
     private static Map<String, String> getRefToRoleMap(Relation relation) {
         Map<String, String> refToRole = new TreeMap<>();
diff --git a/test/unit/org/openstreetmap/josm/actions/ExitActionTest.java b/test/unit/org/openstreetmap/josm/actions/ExitActionTest.java
index c6c4780728..a60d33ea24 100644
--- a/test/unit/org/openstreetmap/josm/actions/ExitActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/ExitActionTest.java
@@ -13,6 +13,7 @@ import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.io.SaveLayersDialog;
 import org.openstreetmap.josm.gui.progress.swing.ProgressMonitorExecutor;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.ImageProvider;
 
 import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
@@ -25,6 +26,7 @@ import mockit.MockUp;
 /**
  * Unit tests for class {@link ExitAction}.
  */
+@BasicPreferences
 final class ExitActionTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/actions/FullscreenToggleActionTest.java b/test/unit/org/openstreetmap/josm/actions/FullscreenToggleActionTest.java
index e03f5a4cc7..1d62fbd117 100644
--- a/test/unit/org/openstreetmap/josm/actions/FullscreenToggleActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/FullscreenToggleActionTest.java
@@ -6,10 +6,12 @@ import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Test {@link FullscreenToggleAction}
  */
+@BasicPreferences
 class FullscreenToggleActionTest {
     /**
      * Setup test.
@@ -29,3 +31,4 @@ class FullscreenToggleActionTest {
         action.actionPerformed(null);
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/JoinAreasActionTest.java b/test/unit/org/openstreetmap/josm/actions/JoinAreasActionTest.java
index a6630f2861..6b095ebda6 100644
--- a/test/unit/org/openstreetmap/josm/actions/JoinAreasActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/JoinAreasActionTest.java
@@ -35,6 +35,9 @@ import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.io.IllegalDataException;
 import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.HTTP;
+import org.openstreetmap.josm.testutils.annotations.Territories;
 import org.openstreetmap.josm.tools.MultiMap;
 import org.openstreetmap.josm.tools.Utils;
 
@@ -43,6 +46,9 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests of {@link JoinAreasAction} class.
  */
+@BasicPreferences
+@HTTP
+@Territories(Territories.Initialize.ALL)
 class JoinAreasActionTest {
 
     /**
@@ -50,7 +56,7 @@ class JoinAreasActionTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().main().projection().preferences();
+    public JOSMTestRules test = new JOSMTestRules().main().projection().territories();
 
     /**
      * Non-regression test for bug #9599.
@@ -270,3 +276,4 @@ class JoinAreasActionTest {
         return n1.hasEqualSemanticAttributes(n2);
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/JoinNodeWayActionTest.java b/test/unit/org/openstreetmap/josm/actions/JoinNodeWayActionTest.java
index 680ffad9ce..148f033e3b 100644
--- a/test/unit/org/openstreetmap/josm/actions/JoinNodeWayActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/JoinNodeWayActionTest.java
@@ -27,6 +27,9 @@ import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.HTTP;
+import org.openstreetmap.josm.testutils.annotations.Territories;
 import org.openstreetmap.josm.tools.Geometry;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -34,13 +37,16 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests for class {@link JoinNodeWayAction}.
  */
+@BasicPreferences
+@HTTP
+@Territories(Territories.Initialize.ALL)
 final class JoinNodeWayActionTest {
     /**
      * Setup test.
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().projection().main().preferences();
+    public JOSMTestRules test = new JOSMTestRules().projection().main();
 
     private void setupMapView(DataSet ds) {
         // setup a reasonable size for the edit window
@@ -243,3 +249,4 @@ final class JoinNodeWayActionTest {
     }
 
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/MergeLayerActionTest.java b/test/unit/org/openstreetmap/josm/actions/MergeLayerActionTest.java
index f29c869887..acec378b36 100644
--- a/test/unit/org/openstreetmap/josm/actions/MergeLayerActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/MergeLayerActionTest.java
@@ -20,6 +20,7 @@ import org.openstreetmap.josm.gui.layer.LayerManagerTest.TestLayer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.widgets.JosmComboBox;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.testutils.mockers.ExtendedDialogMocker;
 import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
 
@@ -28,6 +29,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests for class {@link MergeLayerAction}.
  */
+@BasicPreferences
 public class MergeLayerActionTest {
 
     /**
@@ -123,3 +125,4 @@ public class MergeLayerActionTest {
         assertEquals("Select target layer", invocationLogEntry[2]);
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/PurgeActionTest.java b/test/unit/org/openstreetmap/josm/actions/PurgeActionTest.java
index a201b227b8..f9e0278aaf 100644
--- a/test/unit/org/openstreetmap/josm/actions/PurgeActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/PurgeActionTest.java
@@ -20,10 +20,16 @@ import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.HTTP;
+import org.openstreetmap.josm.testutils.annotations.Territories;
 
 /**
  * Unit tests for class {@link PurgeAction}.
  */
+@BasicPreferences
+@HTTP
+@Territories(Territories.Initialize.ALL)
 class PurgeActionTest {
 
     /**
@@ -31,7 +37,7 @@ class PurgeActionTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().main();
+    public JOSMTestRules test = new JOSMTestRules().main().projection();
 
     /**
      * Non-regression test for ticket #12038.
@@ -65,3 +71,4 @@ class PurgeActionTest {
         }
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/SelectAllActionTest.java b/test/unit/org/openstreetmap/josm/actions/SelectAllActionTest.java
index 73508d5c86..dcd9fd9072 100644
--- a/test/unit/org/openstreetmap/josm/actions/SelectAllActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/SelectAllActionTest.java
@@ -10,10 +10,12 @@ import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link SelectAllAction}.
  */
+@BasicPreferences
 final class SelectAllActionTest {
 
     /**
@@ -21,7 +23,7 @@ final class SelectAllActionTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules rules = new JOSMTestRules().preferences().projection().main();
+    public JOSMTestRules rules = new JOSMTestRules().projection().main();
 
     /**
      * Unit test of {@link SelectAllAction#actionPerformed} method.
@@ -36,3 +38,4 @@ final class SelectAllActionTest {
         assertEquals(6, ds.getSelected().size());
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/SelectByInternalPointActionTest.java b/test/unit/org/openstreetmap/josm/actions/SelectByInternalPointActionTest.java
index c3e709b7fe..d24eed62f5 100644
--- a/test/unit/org/openstreetmap/josm/actions/SelectByInternalPointActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/SelectByInternalPointActionTest.java
@@ -21,10 +21,12 @@ import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import net.trajano.commons.testing.UtilityClassTestUtil;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link SelectByInternalPointAction}.
  */
+@BasicPreferences
 final class SelectByInternalPointActionTest {
 
     /**
@@ -32,7 +34,7 @@ final class SelectByInternalPointActionTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules rules = new JOSMTestRules().preferences().projection().main();
+    public JOSMTestRules rules = new JOSMTestRules().projection().main();
 
     /**
      * Tests that {@code SelectByInternalPointAction} satisfies utility class criteria.
@@ -126,3 +128,4 @@ final class SelectByInternalPointActionTest {
         assertEquals(4, ds.getSelected().size());
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/SessionLoadActionTest.java b/test/unit/org/openstreetmap/josm/actions/SessionLoadActionTest.java
index a224244dba..7551f874c7 100644
--- a/test/unit/org/openstreetmap/josm/actions/SessionLoadActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/SessionLoadActionTest.java
@@ -11,10 +11,12 @@ import org.openstreetmap.josm.gui.layer.TMSLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link SessionLoadAction}.
  */
+@BasicPreferences
 class SessionLoadActionTest {
 
     /**
@@ -35,3 +37,4 @@ class SessionLoadActionTest {
                 ImageryType.TMS.getTypeString(), null, null))));
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/SimplifyWayActionTest.java b/test/unit/org/openstreetmap/josm/actions/SimplifyWayActionTest.java
index 65842499e7..1fccfbc3de 100644
--- a/test/unit/org/openstreetmap/josm/actions/SimplifyWayActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/SimplifyWayActionTest.java
@@ -29,6 +29,7 @@ import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.io.IllegalDataException;
 import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.Utils;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -36,6 +37,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests for class {@link SimplifyWayAction}.
  */
+@BasicPreferences
 final class SimplifyWayActionTest {
 
     /** Class under test. */
@@ -107,3 +109,4 @@ final class SimplifyWayActionTest {
         assertEquals(Collections.singleton(n1), deleteCommands.iterator().next().getParticipatingPrimitives());
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/SplitWayActionTest.java b/test/unit/org/openstreetmap/josm/actions/SplitWayActionTest.java
index c7941c5707..31d43cdb87 100644
--- a/test/unit/org/openstreetmap/josm/actions/SplitWayActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/SplitWayActionTest.java
@@ -20,10 +20,12 @@ import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link SplitWayAction}.
  */
+@BasicPreferences
 final class SplitWayActionTest {
 
     /**
@@ -132,3 +134,4 @@ final class SplitWayActionTest {
         assertSame(4, dataSet.getWays().size(), String.format("Found %d ways after split action instead of 4.", dataSet.getWays().size()));
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/UnGlueActionTest.java b/test/unit/org/openstreetmap/josm/actions/UnGlueActionTest.java
index de2f9cb541..739f99606f 100644
--- a/test/unit/org/openstreetmap/josm/actions/UnGlueActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/UnGlueActionTest.java
@@ -16,10 +16,12 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link UnGlueAction}.
  */
+@BasicPreferences
 final class UnGlueActionTest {
 
     /** Class under test. */
@@ -30,7 +32,7 @@ final class UnGlueActionTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().main().projection().preferences();
+    public JOSMTestRules test = new JOSMTestRules().main().projection();
 
     /**
      * Setup test.
@@ -142,3 +144,4 @@ final class UnGlueActionTest {
         }
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTaskTest.java b/test/unit/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTaskTest.java
index d5c514c34a..0876596848 100644
--- a/test/unit/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTaskTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTaskTest.java
@@ -10,11 +10,13 @@ import java.util.concurrent.ExecutionException;
 import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.testutils.annotations.BasicWiremock;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link DownloadOsmTask}.
  */
 @BasicWiremock
+@BasicPreferences
 class DownloadOsmTaskTest extends AbstractDownloadTaskTestParent {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/actions/downloadtasks/DownloadTaskListTest.java b/test/unit/org/openstreetmap/josm/actions/downloadtasks/DownloadTaskListTest.java
index 21d4f7bf55..db00f25610 100644
--- a/test/unit/org/openstreetmap/josm/actions/downloadtasks/DownloadTaskListTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/downloadtasks/DownloadTaskListTest.java
@@ -8,25 +8,16 @@ import java.awt.geom.Area;
 import java.util.Collections;
 
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link DownloadTaskList}.
  */
+@BasicPreferences
 class DownloadTaskListTest {
-
-    /**
-     * Setup test.
-     */
-    @RegisterExtension
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules();
-
     /**
      * Unit test of {@code DownloadTaskList#DownloadTaskList}.
      */
@@ -53,3 +44,4 @@ class DownloadTaskListTest {
         assertTrue(list.getDownloadedPrimitives().isEmpty());
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/mapmode/AddNoteActionTest.java b/test/unit/org/openstreetmap/josm/actions/mapmode/AddNoteActionTest.java
index 397e2526f8..145dc0defb 100644
--- a/test/unit/org/openstreetmap/josm/actions/mapmode/AddNoteActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/mapmode/AddNoteActionTest.java
@@ -14,10 +14,12 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link AddNoteAction}.
  */
+@BasicPreferences
 class AddNoteActionTest {
 
     /**
@@ -46,3 +48,4 @@ class AddNoteActionTest {
         }
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/mapmode/DeleteActionTest.java b/test/unit/org/openstreetmap/josm/actions/mapmode/DeleteActionTest.java
index 5573a73f23..7be9d47520 100644
--- a/test/unit/org/openstreetmap/josm/actions/mapmode/DeleteActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/mapmode/DeleteActionTest.java
@@ -15,10 +15,12 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link DeleteAction}.
  */
+@BasicPreferences
 class DeleteActionTest {
 
     /**
@@ -55,3 +57,4 @@ class DeleteActionTest {
         TestUtils.superficialEnumCodeCoverage(DeleteMode.class);
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/mapmode/DrawActionTest.java b/test/unit/org/openstreetmap/josm/actions/mapmode/DrawActionTest.java
index 1907155524..5ad0f10f64 100644
--- a/test/unit/org/openstreetmap/josm/actions/mapmode/DrawActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/mapmode/DrawActionTest.java
@@ -28,10 +28,12 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link DrawAction}.
  */
+@BasicPreferences
 class DrawActionTest {
 
     /**
@@ -103,3 +105,4 @@ class DrawActionTest {
         }
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/mapmode/ExtrudeActionTest.java b/test/unit/org/openstreetmap/josm/actions/mapmode/ExtrudeActionTest.java
index fbc4dec9ef..2452a1ca85 100644
--- a/test/unit/org/openstreetmap/josm/actions/mapmode/ExtrudeActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/mapmode/ExtrudeActionTest.java
@@ -15,10 +15,12 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link ExtrudeAction}.
  */
+@BasicPreferences
 class ExtrudeActionTest {
 
     /**
@@ -55,3 +57,4 @@ class ExtrudeActionTest {
         TestUtils.superficialEnumCodeCoverage(Mode.class);
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/mapmode/ImproveWayAccuracyActionTest.java b/test/unit/org/openstreetmap/josm/actions/mapmode/ImproveWayAccuracyActionTest.java
index a31055d93c..0ab7735024 100644
--- a/test/unit/org/openstreetmap/josm/actions/mapmode/ImproveWayAccuracyActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/mapmode/ImproveWayAccuracyActionTest.java
@@ -15,10 +15,12 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link ImproveWayAccuracyAction}.
  */
+@BasicPreferences
 class ImproveWayAccuracyActionTest {
 
     /**
@@ -55,3 +57,4 @@ class ImproveWayAccuracyActionTest {
         TestUtils.superficialEnumCodeCoverage(State.class);
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/mapmode/ParallelWayActionTest.java b/test/unit/org/openstreetmap/josm/actions/mapmode/ParallelWayActionTest.java
index 0087a928ac..ea54d3fe85 100644
--- a/test/unit/org/openstreetmap/josm/actions/mapmode/ParallelWayActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/mapmode/ParallelWayActionTest.java
@@ -16,10 +16,12 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link ParallelWayAction}.
  */
+@BasicPreferences
 class ParallelWayActionTest {
 
     /**
@@ -64,3 +66,4 @@ class ParallelWayActionTest {
         TestUtils.superficialEnumCodeCoverage(Modifier.class);
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/mapmode/PlayHeadDragModeTest.java b/test/unit/org/openstreetmap/josm/actions/mapmode/PlayHeadDragModeTest.java
index 23fa6922f3..836471a8a4 100644
--- a/test/unit/org/openstreetmap/josm/actions/mapmode/PlayHeadDragModeTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/mapmode/PlayHeadDragModeTest.java
@@ -14,10 +14,12 @@ import org.openstreetmap.josm.gui.layer.markerlayer.PlayHeadMarker;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link PlayHeadDragMode}.
  */
+@BasicPreferences
 class PlayHeadDragModeTest {
 
     /**
@@ -46,3 +48,4 @@ class PlayHeadDragModeTest {
         }
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/mapmode/SelectActionTest.java b/test/unit/org/openstreetmap/josm/actions/mapmode/SelectActionTest.java
index 046ba5d151..cb111aa958 100644
--- a/test/unit/org/openstreetmap/josm/actions/mapmode/SelectActionTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/mapmode/SelectActionTest.java
@@ -26,6 +26,7 @@ import org.openstreetmap.josm.gui.layer.MainLayerManager;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.ReflectionUtils;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -33,6 +34,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests for class {@link SelectAction}.
  */
+@BasicPreferences
 class SelectActionTest {
 
     boolean nodesMerged;
@@ -161,3 +163,4 @@ class SelectActionTest {
         TestUtils.superficialEnumCodeCoverage(SelectActionCursor.class);
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/actions/upload/FixDataHookTest.java b/test/unit/org/openstreetmap/josm/actions/upload/FixDataHookTest.java
index a60e8211fa..a8c3cf9327 100644
--- a/test/unit/org/openstreetmap/josm/actions/upload/FixDataHookTest.java
+++ b/test/unit/org/openstreetmap/josm/actions/upload/FixDataHookTest.java
@@ -22,10 +22,12 @@ import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link FixDataHook}.
  */
+@BasicPreferences
 class FixDataHookTest {
 
     /**
@@ -127,3 +129,4 @@ class FixDataHookTest {
         assertTrue(r2.hasKey("space_both"));
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/command/SplitWayCommandTest.java b/test/unit/org/openstreetmap/josm/command/SplitWayCommandTest.java
index 6e724d8ec4..1dd480cb86 100644
--- a/test/unit/org/openstreetmap/josm/command/SplitWayCommandTest.java
+++ b/test/unit/org/openstreetmap/josm/command/SplitWayCommandTest.java
@@ -31,10 +31,12 @@ import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests for class {@link SplitWayCommand}.
  */
+@BasicPreferences
 final class SplitWayCommandTest {
 
     /**
@@ -42,7 +44,7 @@ final class SplitWayCommandTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().main().projection().preferences();
+    public JOSMTestRules test = new JOSMTestRules().main().projection();
 
     /**
      * Unit test of {@link SplitWayCommand#findVias}.
@@ -434,3 +436,4 @@ final class SplitWayCommandTest {
     }
 
 }
+
diff --git a/test/unit/org/openstreetmap/josm/data/osm/NodeDataTest.java b/test/unit/org/openstreetmap/josm/data/osm/NodeDataTest.java
index 88c3300f6e..0760332e44 100644
--- a/test/unit/org/openstreetmap/josm/data/osm/NodeDataTest.java
+++ b/test/unit/org/openstreetmap/josm/data/osm/NodeDataTest.java
@@ -1,6 +1,7 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.data.osm;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
@@ -10,12 +11,13 @@ import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 
-import org.junit.Assert;
 import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
+@BasicPreferences
 class NodeDataTest {
 
     @SuppressFBWarnings(value = "OBJECT_DESERIALIZATION")
@@ -37,7 +39,7 @@ class NodeDataTest {
         data.setVersion(14);
         data.setChangesetId(314159);
         final NodeData readData = serializeUnserialize(data);
-        Assert.assertEquals(data.toString(), readData.toString());
+        assertEquals(data.toString(), readData.toString());
     }
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/data/validation/routines/DomainValidatorTestIT.java b/test/unit/org/openstreetmap/josm/data/validation/routines/DomainValidatorTestIT.java
index 74b6876655..16c24a685a 100644
--- a/test/unit/org/openstreetmap/josm/data/validation/routines/DomainValidatorTestIT.java
+++ b/test/unit/org/openstreetmap/josm/data/validation/routines/DomainValidatorTestIT.java
@@ -49,6 +49,7 @@ import java.util.regex.Pattern;
 import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.IntegrationTest;
 import org.openstreetmap.josm.tools.Logging;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -58,6 +59,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  *
  * @version $Revision: 1723861 $
  */
+@IntegrationTest
 class DomainValidatorTestIT {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/data/validation/tests/CrossingWaysTest.java b/test/unit/org/openstreetmap/josm/data/validation/tests/CrossingWaysTest.java
index 30f5e8f8d4..5fdce35a12 100644
--- a/test/unit/org/openstreetmap/josm/data/validation/tests/CrossingWaysTest.java
+++ b/test/unit/org/openstreetmap/josm/data/validation/tests/CrossingWaysTest.java
@@ -25,12 +25,14 @@ import org.openstreetmap.josm.data.validation.tests.CrossingWays.SelfCrossing;
 import org.openstreetmap.josm.data.validation.tests.CrossingWays.Ways;
 import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit test of {@link CrossingWays}.
  */
+@BasicPreferences
 class CrossingWaysTest {
 
     /**
@@ -38,7 +40,7 @@ class CrossingWaysTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules rule = new JOSMTestRules().preferences().projection();
+    public JOSMTestRules rule = new JOSMTestRules().projection();
 
     private static Way newUsableWay(String tags) {
         return TestUtils.newWay(tags, new Node(LatLon.NORTH_POLE), new Node(LatLon.ZERO));
diff --git a/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java b/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java
index 102f5f3118..46f2ca0f91 100644
--- a/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java
+++ b/test/unit/org/openstreetmap/josm/data/validation/tests/MapCSSTagCheckerTest.java
@@ -42,6 +42,7 @@ import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
 import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.ParseException;
 import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.Logging;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -49,6 +50,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * JUnit Test of {@link MapCSSTagChecker}.
  */
+@BasicPreferences
 class MapCSSTagCheckerTest {
 
     /**
@@ -56,7 +58,7 @@ class MapCSSTagCheckerTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().projection().territories().preferences();
+    public JOSMTestRules test = new JOSMTestRules().projection().territories();
 
     /**
      * Setup test.
diff --git a/test/unit/org/openstreetmap/josm/data/validation/tests/MultipolygonTestTest.java b/test/unit/org/openstreetmap/josm/data/validation/tests/MultipolygonTestTest.java
index 3d3dd861b7..a97c7114b7 100644
--- a/test/unit/org/openstreetmap/josm/data/validation/tests/MultipolygonTestTest.java
+++ b/test/unit/org/openstreetmap/josm/data/validation/tests/MultipolygonTestTest.java
@@ -15,10 +15,12 @@ import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * JUnit Test of Multipolygon validation test.
  */
+@BasicPreferences
 class MultipolygonTestTest {
 
 
@@ -27,7 +29,7 @@ class MultipolygonTestTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().projection().mapStyles().presets().main().preferences();
+    public JOSMTestRules test = new JOSMTestRules().projection().mapStyles().presets().main();
 
     /**
      * Test all error cases manually created in multipolygon.osm.
@@ -70,3 +72,4 @@ class MultipolygonTestTest {
         }
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/data/validation/tests/TagCheckerTest.java b/test/unit/org/openstreetmap/josm/data/validation/tests/TagCheckerTest.java
index ab467d180a..0f3aff2ba1 100644
--- a/test/unit/org/openstreetmap/josm/data/validation/tests/TagCheckerTest.java
+++ b/test/unit/org/openstreetmap/josm/data/validation/tests/TagCheckerTest.java
@@ -23,10 +23,12 @@ import org.openstreetmap.josm.data.validation.TestError;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * JUnit Test of {@link TagChecker}.
  */
+@BasicPreferences
 class TagCheckerTest {
 
     /**
@@ -391,3 +393,4 @@ class TagCheckerTest {
         assertFalse(TagChecker.containsUnusualUnicodeCharacter("name", "Yuułuʔiłʔatḥ Lands"));
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/data/validation/tests/TurnRestrictionTestTest.java b/test/unit/org/openstreetmap/josm/data/validation/tests/TurnRestrictionTestTest.java
index e036a42c73..73337822aa 100644
--- a/test/unit/org/openstreetmap/josm/data/validation/tests/TurnRestrictionTestTest.java
+++ b/test/unit/org/openstreetmap/josm/data/validation/tests/TurnRestrictionTestTest.java
@@ -6,10 +6,12 @@ import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * JUnit Test of turn restriction validation test.
  */
+@BasicPreferences
 class TurnRestrictionTestTest {
 
     private static final TurnrestrictionTest TURNRESTRICTION_TEST = new TurnrestrictionTest();
@@ -33,3 +35,4 @@ class TurnRestrictionTestTest {
                 name -> name.startsWith("E"), TURNRESTRICTION_TEST, RELATION_TEST);
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/gui/MainApplicationTest.java b/test/unit/org/openstreetmap/josm/gui/MainApplicationTest.java
index 7afa85a3cc..ede06c3684 100644
--- a/test/unit/org/openstreetmap/josm/gui/MainApplicationTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/MainApplicationTest.java
@@ -44,6 +44,7 @@ import org.openstreetmap.josm.plugins.PluginListParseException;
 import org.openstreetmap.josm.plugins.PluginListParser;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.PlatformManager;
 import org.openstreetmap.josm.tools.Shortcut;
@@ -53,6 +54,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests of {@link MainApplication} class.
  */
+@BasicPreferences
 public class MainApplicationTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/MapScalerTest.java b/test/unit/org/openstreetmap/josm/gui/MapScalerTest.java
index eed8d2c0c2..bb80a7215d 100644
--- a/test/unit/org/openstreetmap/josm/gui/MapScalerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/MapScalerTest.java
@@ -14,12 +14,14 @@ import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.MapScaler.AccessibleMapScaler;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link MapScaler} class.
  */
+@BasicPreferences
 class MapScalerTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/NavigatableComponentTest.java b/test/unit/org/openstreetmap/josm/gui/NavigatableComponentTest.java
index bced2a293c..5d8964c8c0 100644
--- a/test/unit/org/openstreetmap/josm/gui/NavigatableComponentTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/NavigatableComponentTest.java
@@ -24,6 +24,7 @@ import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.projection.ProjectionRegistry;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
@@ -32,6 +33,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  * @author Michael Zangl
  *
  */
+@BasicPreferences
 class NavigatableComponentTest {
 
     private static final class NavigatableComponentMock extends NavigatableComponent {
@@ -55,7 +57,7 @@ class NavigatableComponentTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().projection();
+    public JOSMTestRules test = new JOSMTestRules().projection();
 
     /**
      * Create a new, fresh {@link NavigatableComponent}
diff --git a/test/unit/org/openstreetmap/josm/gui/TableCellRendererTest.java b/test/unit/org/openstreetmap/josm/gui/TableCellRendererTest.java
index 53fa17f273..aec7b65fb2 100644
--- a/test/unit/org/openstreetmap/josm/gui/TableCellRendererTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/TableCellRendererTest.java
@@ -18,6 +18,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.ReflectionUtils;
 
@@ -39,6 +40,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  *
  * @see <a href="https://josm.openstreetmap.de/ticket/6301">#6301</a>
  */
+@BasicPreferences
 class TableCellRendererTest {
 
     // list of classes that cannot be easily tested and are verified either manually or another unit tests
diff --git a/test/unit/org/openstreetmap/josm/gui/datatransfer/OsmTransferHandlerTest.java b/test/unit/org/openstreetmap/josm/gui/datatransfer/OsmTransferHandlerTest.java
index c58dcc28b9..c1b02094e1 100644
--- a/test/unit/org/openstreetmap/josm/gui/datatransfer/OsmTransferHandlerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/datatransfer/OsmTransferHandlerTest.java
@@ -18,17 +18,17 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link OsmTransferHandler} class.
  */
+// Prefs for OSM primitives
+@BasicPreferences
 class OsmTransferHandlerTest {
-    /**
-     * Prefs to use OSM primitives
-     */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().projection().main();
+    public JOSMTestRules test = new JOSMTestRules().projection().main();
 
     private final OsmTransferHandler transferHandler = new OsmTransferHandler();
 
@@ -72,3 +72,4 @@ class OsmTransferHandlerTest {
         assertEquals("ok", n.get("test"));
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/CommandStackDialogTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/CommandStackDialogTest.java
index 56a49140ec..da81bee6d4 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/CommandStackDialogTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/CommandStackDialogTest.java
@@ -16,10 +16,12 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link CommandStackDialog} class.
  */
+@BasicPreferences
 class CommandStackDialogTest {
 
     /**
@@ -27,7 +29,7 @@ class CommandStackDialogTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().main().projection().preferences();
+    public JOSMTestRules test = new JOSMTestRules().main().projection();
 
     /**
      * Unit test of {@link CommandStackDialog} class - empty case.
@@ -113,3 +115,4 @@ class CommandStackDialogTest {
         }
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/ConflictDialogTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/ConflictDialogTest.java
index 26eca27009..33b544da57 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/ConflictDialogTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/ConflictDialogTest.java
@@ -21,10 +21,12 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link ConflictDialog} class.
  */
+@BasicPreferences
 class ConflictDialogTest {
 
     /**
@@ -73,3 +75,4 @@ class ConflictDialogTest {
         cp.visit(r);
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/InspectPrimitiveDialogTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/InspectPrimitiveDialogTest.java
index b338d3f330..ff2d873346 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/InspectPrimitiveDialogTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/InspectPrimitiveDialogTest.java
@@ -23,10 +23,12 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link InspectPrimitiveDialog} class.
  */
+@BasicPreferences
 class InspectPrimitiveDialogTest {
 
     /**
@@ -170,3 +172,4 @@ class InspectPrimitiveDialogTest {
         }
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/MapPaintDialogTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/MapPaintDialogTest.java
index e395bf7378..e37b587ae7 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/MapPaintDialogTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/MapPaintDialogTest.java
@@ -9,10 +9,12 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link MapPaintDialog} class.
  */
+@BasicPreferences
 class MapPaintDialogTest {
 
     /**
@@ -31,3 +33,4 @@ class MapPaintDialogTest {
         MainApplication.getMap().mapPaintDialog.new InfoAction().actionPerformed(null);
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/MinimapDialogTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/MinimapDialogTest.java
index c2399a6aa3..7bec43b9cf 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/MinimapDialogTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/MinimapDialogTest.java
@@ -2,11 +2,11 @@
 package org.openstreetmap.josm.gui.dialogs;
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.Color;
@@ -27,8 +27,8 @@ import javax.swing.JMenuItem;
 import javax.swing.JPopupMenu;
 
 import org.awaitility.Awaitility;
-import org.junit.Rule;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.DataSource;
@@ -48,26 +48,30 @@ import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.ImagePatternMatching;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.FakeImagery;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link MinimapDialog} class.
  */
-public class MinimapDialogTest {
+@BasicPreferences
+@FakeImagery
+class MinimapDialogTest {
 
     /**
      * Setup tests
      */
-    @Rule
+    @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules josmTestRules = new JOSMTestRules().main().projection().fakeImagery();
+    public JOSMTestRules josmTestRules = new JOSMTestRules().main().projection();
 
     /**
      * Unit test of {@link MinimapDialog} class.
      */
     @Test
-    public void testMinimapDialog() {
+    void testMinimapDialog() {
         MinimapDialog dlg = new MinimapDialog();
         dlg.showDialog();
         assertTrue(dlg.isVisible());
@@ -101,12 +105,12 @@ public class MinimapDialogTest {
                 boolean isSelected = ((JMenuItem) c).isSelected();
                 assertEquals(equalText, isSelected);
                 if (equalText) {
-                    assertFalse("Second selected source found", found);
+                    assertFalse(found, "Second selected source found");
                     found = true;
                 }
             }
         }
-        assertTrue("Selected source not found in menu", found);
+        assertTrue(found, "Selected source not found in menu");
     }
 
     protected void clickSourceMenuItemByLabel(final String label) {
@@ -198,7 +202,7 @@ public class MinimapDialogTest {
      * @throws Exception if any error occurs
      */
     @Test
-    public void testSourceSwitching() throws Exception {
+    void testSourceSwitching() throws Exception {
         // relevant prefs starting out empty, should choose the first source and have shown download area enabled
         // (not that there's a data layer for it to use)
 
@@ -245,7 +249,7 @@ public class MinimapDialogTest {
      * @throws Exception if any error occurs
      */
     @Test
-    public void testRefreshSourcesRetainsSelection() throws Exception {
+    void testRefreshSourcesRetainsSelection() throws Exception {
         // relevant prefs starting out empty, should choose the first source and have shown download area enabled
         // (not that there's a data layer for it to use)
 
@@ -283,7 +287,7 @@ public class MinimapDialogTest {
      * @throws Exception if any error occurs
      */
     @Test
-    public void testRemovedSourceStillSelected() throws Exception {
+    void testRemovedSourceStillSelected() throws Exception {
         // relevant prefs starting out empty, should choose the first source and have shown download area enabled
         // (not that there's a data layer for it to use)
 
@@ -316,7 +320,7 @@ public class MinimapDialogTest {
      * @throws Exception if any error occurs
      */
     @Test
-    public void testTileSourcesFromCurrentLayers() throws Exception {
+    void testTileSourcesFromCurrentLayers() throws Exception {
         // relevant prefs starting out empty, should choose the first (ImageryLayerInfo) source and have shown download area enabled
         // (not that there's a data layer for it to use)
 
@@ -450,7 +454,7 @@ public class MinimapDialogTest {
      * @throws Exception if any error occurs
      */
     @Test
-    public void testSourcePrefObeyed() throws Exception {
+    void testSourcePrefObeyed() throws Exception {
         Config.getPref().put("slippy_map_chooser.mapstyle", "Green Tiles");
 
         this.setUpMiniMap();
@@ -477,7 +481,7 @@ public class MinimapDialogTest {
      * @throws Exception if any error occurs
      */
     @Test
-    public void testSourcePrefInvalid() throws Exception {
+    void testSourcePrefInvalid() throws Exception {
         Config.getPref().put("slippy_map_chooser.mapstyle", "Hooloovoo Tiles");
 
         this.setUpMiniMap();
@@ -499,7 +503,7 @@ public class MinimapDialogTest {
      * @throws Exception if any error occurs
      */
     @Test
-    public void testViewportAspectRatio() throws Exception {
+    void testViewportAspectRatio() throws Exception {
         // Add a test layer to the layer manager to get the MapFrame & MapView
         MainApplication.getLayerManager().addLayer(new TestLayer());
 
@@ -545,8 +549,8 @@ public class MinimapDialogTest {
         // (within a tolerance for numerical error) the number of pixels on the left of the viewport marker
         // should equal the number on the right
         assertTrue(
-            "Viewport marker not horizontally centered",
-            Math.abs(rowMatcher.group(1).length() - rowMatcher.group(3).length()) < 4
+            Math.abs(rowMatcher.group(1).length() - rowMatcher.group(3).length()) < 4,
+            "Viewport marker not horizontally centered"
         );
 
         Matcher colMatcher = ImagePatternMatching.columnMatch(
@@ -560,14 +564,14 @@ public class MinimapDialogTest {
         // (within a tolerance for numerical error) the number of pixels on the top of the viewport marker
         // should equal the number on the bottom
         assertTrue(
-            "Viewport marker not vertically centered",
-            Math.abs(colMatcher.group(1).length() - colMatcher.group(3).length()) < 4
+            Math.abs(colMatcher.group(1).length() - colMatcher.group(3).length()) < 4,
+            "Viewport marker not vertically centered"
         );
 
         // (within a tolerance for numerical error) the viewport marker should be square
         assertTrue(
-            "Viewport marker not square",
-            Math.abs(colMatcher.group(2).length() - rowMatcher.group(2).length()) < 4
+            Math.abs(colMatcher.group(2).length() - rowMatcher.group(2).length()) < 4,
+            "Viewport marker not square"
         );
 
         // now change the mapView size
@@ -590,8 +594,8 @@ public class MinimapDialogTest {
             true
         );
         assertTrue(
-            "Viewport marker not horizontally centered",
-            Math.abs(rowMatcher.group(1).length() - rowMatcher.group(3).length()) < 4
+            Math.abs(rowMatcher.group(1).length() - rowMatcher.group(3).length()) < 4,
+            "Viewport marker not horizontally centered"
         );
 
         colMatcher = ImagePatternMatching.columnMatch(
@@ -602,8 +606,8 @@ public class MinimapDialogTest {
             true
         );
         assertTrue(
-            "Viewport marker not vertically centered",
-            Math.abs(colMatcher.group(1).length() - colMatcher.group(3).length()) < 4
+            Math.abs(colMatcher.group(1).length() - colMatcher.group(3).length()) < 4,
+            "Viewport marker not vertically centered"
         );
 
         try {
@@ -613,8 +617,8 @@ public class MinimapDialogTest {
         }
 
         assertTrue(
-            "Viewport marker not 2:1 aspect ratio",
-            Math.abs(colMatcher.group(2).length() - (rowMatcher.group(2).length()*2.0)) < 5
+            Math.abs(colMatcher.group(2).length() - (rowMatcher.group(2).length()*2.0)) < 5,
+            "Viewport marker not 2:1 aspect ratio"
         );
     }
 
@@ -623,11 +627,11 @@ public class MinimapDialogTest {
         boolean afterSeparator = false;
         for (Component c: menu.getComponents()) {
             if (JPopupMenu.Separator.class.isInstance(c)) {
-                assertFalse("More than one separator before target item", afterSeparator);
+                assertFalse(afterSeparator, "More than one separator before target item");
                 afterSeparator = true;
             } else if (((JMenuItem) c).getText().equals(tr("Show downloaded area"))) {
-                assertTrue("Separator not found before target item", afterSeparator);
-                assertTrue("Target item doesn't appear to be a JCheckBoxMenuItem", JCheckBoxMenuItem.class.isInstance(c));
+                assertTrue(afterSeparator, "Separator not found before target item");
+                assertTrue(JCheckBoxMenuItem.class.isInstance(c), "Target item doesn't appear to be a JCheckBoxMenuItem");
                 return (JCheckBoxMenuItem) c;
             }
         }
@@ -640,7 +644,7 @@ public class MinimapDialogTest {
      * @throws Exception if any error occurs
      */
     @Test
-    public void testShowDownloadedArea() throws Exception {
+    void testShowDownloadedArea() throws Exception {
         Config.getPref().put("slippy_map_chooser.mapstyle", "Green Tiles");
         Config.getPref().putBoolean("slippy_map_chooser.show_downloaded_area", false);
 
@@ -799,7 +803,7 @@ public class MinimapDialogTest {
      * @throws Exception if any error occurs
      */
     @Test
-    public void testShowDownloadedAreaLayerSwitching() throws Exception {
+    void testShowDownloadedAreaLayerSwitching() throws Exception {
         Config.getPref().put("slippy_map_chooser.mapstyle", "Green Tiles");
         Config.getPref().putBoolean("slippy_map_chooser.show_downloaded_area", true);
 
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetContentPanelTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetContentPanelTest.java
index 146c5a3bad..2b94122872 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetContentPanelTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetContentPanelTest.java
@@ -8,10 +8,12 @@ import org.openstreetmap.josm.testutils.JOSMTestRules;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link ChangesetContentPanel} class.
  */
+@BasicPreferences
 class ChangesetContentPanelTest {
 
     /**
@@ -19,7 +21,7 @@ class ChangesetContentPanelTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().main();
+    public JOSMTestRules test = new JOSMTestRules().main();
 
     /**
      * Unit test of {@link ChangesetContentPanel#ChangesetContentPanel}.
@@ -29,3 +31,4 @@ class ChangesetContentPanelTest {
         assertNotNull(new ChangesetContentPanel());
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/layer/CycleLayerActionTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/layer/CycleLayerActionTest.java
index 62febb878c..62cbc6606a 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/layer/CycleLayerActionTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/layer/CycleLayerActionTest.java
@@ -1,12 +1,12 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.dialogs.layer;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
 import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -17,17 +17,21 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.FakeImagery;
 
 /**
  * Test class for {@link CycleLayerDownAction}
  *
  * @author Taylor Smock
  */
-public class CycleLayerActionTest {
+@BasicPreferences
+@FakeImagery
+class CycleLayerActionTest {
     /** Layers need a projection */
-    @Rule
+    @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().main().preferences().projection().fakeImagery();
+    public JOSMTestRules test = new JOSMTestRules().main().projection();
 
     private CycleLayerDownAction cycleDown;
     private CycleLayerUpAction cycleUp;
@@ -36,7 +40,7 @@ public class CycleLayerActionTest {
     /**
      * Set up common items (make layers, etc.)
      */
-    @Before
+    @BeforeEach
     public void setUp() {
         cycleDown = new CycleLayerDownAction();
         cycleUp = new CycleLayerUpAction();
@@ -50,7 +54,7 @@ public class CycleLayerActionTest {
      * Test going down from the bottom
      */
     @Test
-    public void testDownBottom() {
+    void testDownBottom() {
         manager.setActiveLayer(manager.getLayers().get(0));
         cycleDown.actionPerformed(null);
         assertEquals(manager.getLayers().size() - 1, manager.getLayers().indexOf(manager.getActiveLayer()));
@@ -60,7 +64,7 @@ public class CycleLayerActionTest {
      * Check going up from the top
      */
     @Test
-    public void testUpTop() {
+    void testUpTop() {
         manager.setActiveLayer(manager.getLayers().get(manager.getLayers().size() - 1));
         cycleUp.actionPerformed(null);
         assertEquals(0, manager.getLayers().indexOf(manager.getActiveLayer()));
@@ -70,7 +74,7 @@ public class CycleLayerActionTest {
      * Check going down
      */
     @Test
-    public void testDown() {
+    void testDown() {
         manager.setActiveLayer(manager.getLayers().get(3));
         cycleDown.actionPerformed(null);
         assertEquals(2, manager.getLayers().indexOf(manager.getActiveLayer()));
@@ -80,7 +84,7 @@ public class CycleLayerActionTest {
      * Check going up
      */
     @Test
-    public void testUp() {
+    void testUp() {
         manager.setActiveLayer(manager.getLayers().get(3));
         cycleUp.actionPerformed(null);
         assertEquals(4, manager.getLayers().indexOf(manager.getActiveLayer()));
@@ -90,7 +94,7 @@ public class CycleLayerActionTest {
      * Test no layers
      */
     @Test
-    public void testNoLayers() {
+    void testNoLayers() {
         manager.getLayers().forEach(manager::removeLayer);
         cycleUp.actionPerformed(null);
         cycleDown.actionPerformed(null);
@@ -101,7 +105,7 @@ public class CycleLayerActionTest {
      * Test with an aerial imagery layer
      */
     @Test
-    public void testWithAerialImagery() {
+    void testWithAerialImagery() {
         final ImageryInfo magentaTilesInfo = ImageryLayerInfo.instance.getLayers().stream()
                 .filter(i -> i.getName().equals("Magenta Tiles")).findAny().get();
         ImageryLayer imageryLayer = ImageryLayer.create(magentaTilesInfo);
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/layer/DuplicateActionTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/layer/DuplicateActionTest.java
index 0e95c82738..eb55970417 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/layer/DuplicateActionTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/layer/DuplicateActionTest.java
@@ -8,10 +8,12 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 
 import java.io.InputStream;
 
+import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.io.OsmReader;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
 import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import org.junit.jupiter.api.Test;
@@ -22,6 +24,9 @@ import org.junit.jupiter.api.Test;
 // TMS layer needs prefs. Platform for LayerListDialog shortcuts.
 @BasicPreferences
 class DuplicateActionTest {
+    // Needed for layer cleanup
+    @RegisterExtension
+    JOSMTestRules rules = new JOSMTestRules();
     /**
      * Non-regression test for ticket <a href="https://josm.openstreetmap.de/ticket/4539">#4539</a>.
      * @throws Exception if an error occurs
@@ -29,7 +34,7 @@ class DuplicateActionTest {
     @Test
     void testTicket4539() throws Exception {
         try (InputStream is = TestUtils.getRegressionDataStream(4539, "josm_error_#4539.osm.zip")) {
-            OsmDataLayer layer = new OsmDataLayer(OsmReader.parseDataSet(is, null), null, null);
+            OsmDataLayer layer = new OsmDataLayer(OsmReader.parseDataSet(is, null), "DuplicateActionTest#testTicket4539", null);
             OsmDataLayer editLayer = MainApplication.getLayerManager().getEditLayer();
             assertNull(editLayer);
             try {
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityActionTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityActionTest.java
index 1ee10011a2..a9f09a16ce 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityActionTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/layer/LayerVisibilityActionTest.java
@@ -16,17 +16,19 @@ import org.openstreetmap.josm.gui.layer.TMSLayerTest;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link LayerVisibilityAction} class.
  */
+@BasicPreferences
 class LayerVisibilityActionTest {
     /**
      * TMS layer needs prefs. Platform for LayerListDialog shortcuts.
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().projection().main();
+    public JOSMTestRules test = new JOSMTestRules().projection().main();
 
     /**
      * Unit test of {@link LayerVisibilityAction} class.
@@ -95,3 +97,4 @@ class LayerVisibilityActionTest {
         assertEquals(1.0, layer.getOpacity(), 1e-15);
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/properties/PropertiesCellRendererTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/properties/PropertiesCellRendererTest.java
index 61dd6b0dfc..8789edaa7d 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/properties/PropertiesCellRendererTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/properties/PropertiesCellRendererTest.java
@@ -3,30 +3,19 @@ package org.openstreetmap.josm.gui.dialogs.properties;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-import java.util.function.IntFunction;
-
 import javax.swing.JLabel;
 import javax.swing.JTable;
 import javax.swing.table.DefaultTableModel;
+import java.util.function.IntFunction;
 
-import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link PropertiesCellRenderer} class.
  */
+@BasicPreferences
 class PropertiesCellRendererTest {
-
-    /**
-     * Setup test.
-     */
-    @RegisterExtension
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences();
-
     /**
      * Test of color rendering.
      */
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditorTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditorTest.java
index ac2a9d4628..0863e616cb 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditorTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditorTest.java
@@ -22,6 +22,7 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.tagging.TagEditorPanel;
 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -29,6 +30,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests of {@link GenericRelationEditor} class.
  */
+@BasicPreferences
 public class GenericRelationEditorTest {
 
     /**
@@ -36,7 +38,7 @@ public class GenericRelationEditorTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().main();
+    public JOSMTestRules test = new JOSMTestRules().main();
 
     /**
      * Returns a new relation editor for unit tests.
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/AbstractRelationEditorActionTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/AbstractRelationEditorActionTest.java
index 90bd4ec9e7..6ea4fb20f6 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/AbstractRelationEditorActionTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/AbstractRelationEditorActionTest.java
@@ -23,6 +23,7 @@ import org.openstreetmap.josm.gui.tagging.TagEditorModel;
 import org.openstreetmap.josm.gui.tagging.ac.AutoCompletingTextField;
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetHandler;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
@@ -31,13 +32,14 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  * @author Michael Zangl
  */
 @Disabled
+@BasicPreferences
 public abstract class AbstractRelationEditorActionTest {
     /**
      * Platform for tooltips.
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().main();
+    public JOSMTestRules test = new JOSMTestRules().main();
 
     protected OsmDataLayer layer;
 
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/RelationEditorActionsTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/RelationEditorActionsTest.java
index 398de3afc8..1197c8bb3c 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/RelationEditorActionsTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/relation/actions/RelationEditorActionsTest.java
@@ -14,6 +14,7 @@ import javax.swing.text.JTextComponent;
 import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
+import org.openstreetmap.josm.testutils.annotations.I18n;
 import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
 
 import mockit.Mock;
@@ -22,6 +23,7 @@ import mockit.MockUp;
 /**
  * Unit tests for relation editor actions.
  */
+@I18n
 class RelationEditorActionsTest extends AbstractRelationEditorActionTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationSorterTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationSorterTest.java
index c48563391a..19d6cb4a6a 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationSorterTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/relation/sort/RelationSorterTest.java
@@ -18,12 +18,14 @@ import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.io.IllegalDataException;
 import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link RelationSorter} class.
  */
+@BasicPreferences
 class RelationSorterTest {
 
     private final RelationSorter sorter = new RelationSorter();
@@ -34,7 +36,7 @@ class RelationSorterTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().projection();
+    public JOSMTestRules test = new JOSMTestRules().projection();
 
     /**
      * Load the test data set
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/relation/sort/WayConnectionTypeCalculatorTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/relation/sort/WayConnectionTypeCalculatorTest.java
index 624b829e22..e0d30efcc3 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/relation/sort/WayConnectionTypeCalculatorTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/relation/sort/WayConnectionTypeCalculatorTest.java
@@ -24,12 +24,14 @@ import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.io.IllegalDataException;
 import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link WayConnectionTypeCalculator} class.
  */
+@BasicPreferences
 class WayConnectionTypeCalculatorTest {
 
     private final RelationSorter sorter = new RelationSorter();
@@ -41,7 +43,7 @@ class WayConnectionTypeCalculatorTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().projection();
+    public JOSMTestRules test = new JOSMTestRules().projection();
 
     /**
      * Load the test data set
diff --git a/test/unit/org/openstreetmap/josm/gui/help/HelpBrowserTest.java b/test/unit/org/openstreetmap/josm/gui/help/HelpBrowserTest.java
index 0eb9f795bb..2293527eee 100644
--- a/test/unit/org/openstreetmap/josm/gui/help/HelpBrowserTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/help/HelpBrowserTest.java
@@ -12,6 +12,7 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
 import org.openstreetmap.josm.tools.LanguageInfo.LocaleType;
 import org.openstreetmap.josm.tools.PlatformHook;
@@ -25,6 +26,7 @@ import mockit.Mocked;
 /**
  * Unit tests of {@link HelpBrowser} class.
  */
+@BasicPreferences
 class HelpBrowserTest {
 
     static final String URL_1 = "https://josm.openstreetmap.de/wiki/Help";
@@ -36,7 +38,7 @@ class HelpBrowserTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    static JOSMTestRules test = new JOSMTestRules().preferences().https();
+    static JOSMTestRules test = new JOSMTestRules().https();
 
     static IHelpBrowser newHelpBrowser() {
         return new IHelpBrowser() {
diff --git a/test/unit/org/openstreetmap/josm/gui/history/HistoryBrowserModelTest.java b/test/unit/org/openstreetmap/josm/gui/history/HistoryBrowserModelTest.java
index 2be15c5a66..6331442a04 100644
--- a/test/unit/org/openstreetmap/josm/gui/history/HistoryBrowserModelTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/history/HistoryBrowserModelTest.java
@@ -17,6 +17,7 @@ import org.openstreetmap.josm.data.osm.history.History;
 import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
 import org.openstreetmap.josm.data.osm.history.HistoryNode;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
@@ -25,6 +26,7 @@ import java.awt.Color;
 /**
  * Unit tests of {@link HistoryBrowserModel} class.
  */
+@BasicPreferences
 class HistoryBrowserModelTest {
 
     /**
@@ -32,7 +34,7 @@ class HistoryBrowserModelTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().devAPI().timeout(30000);
+    public JOSMTestRules test = new JOSMTestRules().devAPI().timeout(30000);
 
     /**
      * Test for {@link HistoryBrowserModel#HistoryBrowserModel}.
diff --git a/test/unit/org/openstreetmap/josm/gui/history/HistoryLoadTaskTest.java b/test/unit/org/openstreetmap/josm/gui/history/HistoryLoadTaskTest.java
index 86997dfbce..917aedf335 100644
--- a/test/unit/org/openstreetmap/josm/gui/history/HistoryLoadTaskTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/history/HistoryLoadTaskTest.java
@@ -22,6 +22,7 @@ import org.openstreetmap.josm.io.OsmHistoryReader;
 import org.openstreetmap.josm.io.OsmServerHistoryReader;
 import org.openstreetmap.josm.io.OsmTransferException;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.xml.sax.SAXException;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -29,6 +30,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests of {@link HistoryLoadTask} class.
  */
+@BasicPreferences
 class HistoryLoadTaskTest {
 
     /**
@@ -36,7 +38,7 @@ class HistoryLoadTaskTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().devAPI().timeout(20000);
+    public JOSMTestRules test = new JOSMTestRules().devAPI().timeout(20000);
 
     /**
      * Unit test of {@link HistoryLoadTask#getLoadingMessage}
diff --git a/test/unit/org/openstreetmap/josm/gui/io/DownloadOpenChangesetsTaskTest.java b/test/unit/org/openstreetmap/josm/gui/io/DownloadOpenChangesetsTaskTest.java
index 16d0dcf978..2eac67759f 100644
--- a/test/unit/org/openstreetmap/josm/gui/io/DownloadOpenChangesetsTaskTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/io/DownloadOpenChangesetsTaskTest.java
@@ -19,6 +19,7 @@ import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.UserIdentityManager;
 import org.openstreetmap.josm.gui.oauth.OAuthAuthorizationWizard;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
 import org.openstreetmap.josm.testutils.mockers.WindowMocker;
 import org.openstreetmap.josm.tools.UserCancelException;
@@ -31,6 +32,7 @@ import mockit.MockUp;
 /**
  * Unit tests of {@link DownloadOpenChangesetsTask} class.
  */
+@BasicPreferences
 class DownloadOpenChangesetsTaskTest {
 
     /**
@@ -38,7 +40,7 @@ class DownloadOpenChangesetsTaskTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().devAPI();
+    public JOSMTestRules test = new JOSMTestRules().devAPI();
 
     /**
      * OAuth wizard mocker.
diff --git a/test/unit/org/openstreetmap/josm/gui/io/DownloadPrimitivesTaskTest.java b/test/unit/org/openstreetmap/josm/gui/io/DownloadPrimitivesTaskTest.java
index 47695f6758..43e197c602 100644
--- a/test/unit/org/openstreetmap/josm/gui/io/DownloadPrimitivesTaskTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/io/DownloadPrimitivesTaskTest.java
@@ -14,12 +14,14 @@ import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link DownloadPrimitivesTask} class.
  */
+@BasicPreferences
 class DownloadPrimitivesTaskTest {
 
     /**
@@ -27,7 +29,7 @@ class DownloadPrimitivesTaskTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().devAPI().timeout(20000);
+    public JOSMTestRules test = new JOSMTestRules().devAPI().timeout(20000);
 
     /**
      * Test of {@link DownloadPrimitivesTask} class.
diff --git a/test/unit/org/openstreetmap/josm/gui/io/UploadDialogModelTest.java b/test/unit/org/openstreetmap/josm/gui/io/UploadDialogModelTest.java
index 9223ca87dd..bb08f7221c 100644
--- a/test/unit/org/openstreetmap/josm/gui/io/UploadDialogModelTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/io/UploadDialogModelTest.java
@@ -10,16 +10,18 @@ import org.junit.jupiter.api.Test;
 
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link UploadDialogModel} class.
  */
+@BasicPreferences
 public class UploadDialogModelTest {
     /**
      * Setup tests
      */
     @RegisterExtension
-    public JOSMTestRules test = new JOSMTestRules().preferences().main();
+    public JOSMTestRules test = new JOSMTestRules().main();
 
     /**
      * Test of {@link UploadDialogModel}.
diff --git a/test/unit/org/openstreetmap/josm/gui/io/UploadStrategySelectionPanelTest.java b/test/unit/org/openstreetmap/josm/gui/io/UploadStrategySelectionPanelTest.java
index 2f46704710..84a910aa56 100644
--- a/test/unit/org/openstreetmap/josm/gui/io/UploadStrategySelectionPanelTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/io/UploadStrategySelectionPanelTest.java
@@ -8,12 +8,14 @@ import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.io.UploadStrategy;
 import org.openstreetmap.josm.io.UploadStrategySpecification;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link UploadStrategySelectionPanel} class.
  */
+@BasicPreferences
 class UploadStrategySelectionPanelTest {
 
     /**
@@ -21,7 +23,7 @@ class UploadStrategySelectionPanelTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().devAPI();
+    public JOSMTestRules test = new JOSMTestRules().devAPI();
 
     /**
      * Test of {@link UploadStrategySelectionPanel#UploadStrategySelectionPanel}.
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayerTest.java
index 14ebf64641..a13482bc04 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayerTest.java
@@ -32,12 +32,14 @@ import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Test of the base {@link AbstractTileSourceLayer} class
  */
+@BasicPreferences
 class AbstractTileSourceLayerTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/AutosaveTaskTest.java b/test/unit/org/openstreetmap/josm/gui/layer/AutosaveTaskTest.java
index fa84a4ae91..6ada037c62 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/AutosaveTaskTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/AutosaveTaskTest.java
@@ -29,19 +29,21 @@ import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.layer.AutosaveTask.AutosaveLayerInfo;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests for class {@link AutosaveTask}.
  */
+@BasicPreferences
 class AutosaveTaskTest {
     /**
      * We need preferences and a home directory for this.
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().projection();
+    public JOSMTestRules test = new JOSMTestRules().projection();
 
     private AutosaveTask task;
 
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/GpxLayerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/GpxLayerTest.java
index 98fe1f676d..74d921f986 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/GpxLayerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/GpxLayerTest.java
@@ -35,6 +35,7 @@ import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.widgets.HtmlPanel;
 import org.openstreetmap.josm.io.GpxReaderTest;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.date.DateUtils;
 import org.xml.sax.SAXException;
 
@@ -43,6 +44,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests of {@link GpxLayer} class.
  */
+@BasicPreferences
 public class GpxLayerTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/LayerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/LayerTest.java
index 102a629a5e..d3f8160e3a 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/LayerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/LayerTest.java
@@ -14,6 +14,7 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.data.projection.ProjectionRegistry;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
@@ -21,13 +22,14 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  * Test of the base {@link Layer} class
  * @author Michael Zangl
  */
+@BasicPreferences
 class LayerTest {
     /**
      * We need projection
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().projection();
+    public JOSMTestRules test = new JOSMTestRules().projection();
 
     private Layer testLayer;
 
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/OsmDataLayerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/OsmDataLayerTest.java
index 7629c1318d..70f46f655e 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/OsmDataLayerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/OsmDataLayerTest.java
@@ -35,6 +35,7 @@ import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
 import org.openstreetmap.josm.io.IllegalDataException;
 import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.testutils.mockers.ExtendedDialogMocker;
 import org.openstreetmap.josm.tools.Logging;
 
@@ -43,6 +44,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests of {@link OsmDataLayer} class.
  */
+@BasicPreferences
 class OsmDataLayerTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/TMSLayerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/TMSLayerTest.java
index e1c21890e7..f448860786 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/TMSLayerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/TMSLayerTest.java
@@ -9,12 +9,14 @@ import org.openstreetmap.josm.data.imagery.ImageryInfo;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link TMSLayer} class.
  */
+@BasicPreferences
 public class TMSLayerTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/ValidatorLayerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/ValidatorLayerTest.java
index 0f1f9444f3..759a8ef880 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/ValidatorLayerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/ValidatorLayerTest.java
@@ -6,17 +6,19 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link ValidatorLayer} class.
  */
+@BasicPreferences
 class ValidatorLayerTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/WMSLayerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/WMSLayerTest.java
index b3a72a5129..bbfbb3f773 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/WMSLayerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/WMSLayerTest.java
@@ -10,12 +10,14 @@ import org.openstreetmap.josm.data.imagery.ImageryInfo;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link WMSLayer} class.
  */
+@BasicPreferences
 class WMSLayerTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/WMTSLayerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/WMTSLayerTest.java
index 225dd0bc6a..af264a0538 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/WMTSLayerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/WMTSLayerTest.java
@@ -3,26 +3,18 @@ package org.openstreetmap.josm.gui.layer;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
 import org.openstreetmap.josm.data.imagery.ImageryInfo;
 import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link WMTSLayer} class.
  */
+@BasicPreferences
+@Timeout(20)
 class WMTSLayerTest {
-
-    /**
-     * Setup tests
-     */
-    @RegisterExtension
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().timeout(20000);
-
     /**
      * Unit test of {@link WMTSLayer#WMTSLayer}.
      */
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/geoimage/ImagesLoaderTest.java b/test/unit/org/openstreetmap/josm/gui/layer/geoimage/ImagesLoaderTest.java
index 23f26d730e..c46015e625 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/geoimage/ImagesLoaderTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/geoimage/ImagesLoaderTest.java
@@ -16,20 +16,22 @@ import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.io.GpxReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link ImagesLoader} class.
  */
+@BasicPreferences
 class ImagesLoaderTest {
 
     /**
-     * We need prefs for this.
+     * We need prefs for this. And it also cleans up the layers.
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences();
+    public JOSMTestRules test = new JOSMTestRules();
 
     /**
      * Unit test of {@link ImagesLoader} class.
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/gpx/ConvertToDataLayerActionTest.java b/test/unit/org/openstreetmap/josm/gui/layer/gpx/ConvertToDataLayerActionTest.java
index a824478ab3..32eb057cff 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/gpx/ConvertToDataLayerActionTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/gpx/ConvertToDataLayerActionTest.java
@@ -15,7 +15,6 @@ import java.util.Objects;
 import java.util.stream.Collectors;
 
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.gpx.GpxData;
@@ -28,23 +27,14 @@ import org.openstreetmap.josm.io.GpxReaderTest;
 import org.openstreetmap.josm.io.IllegalDataException;
 import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.spi.preferences.Config;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.xml.sax.SAXException;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
 /**
  * Unit tests of {@link ConvertToDataLayerAction} class.
  */
+@BasicPreferences
 public class ConvertToDataLayerActionTest {
-
-    /**
-     * Setup test.
-     */
-    @RegisterExtension
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules();
-
     /**
      * Tests a conversion from a GPX marker layer to a OSM dataset
      * @throws Exception if the parsing fails
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/gpx/DownloadWmsAlongTrackActionTest.java b/test/unit/org/openstreetmap/josm/gui/layer/gpx/DownloadWmsAlongTrackActionTest.java
index d0ccb1be8b..67242fbb15 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/gpx/DownloadWmsAlongTrackActionTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/gpx/DownloadWmsAlongTrackActionTest.java
@@ -2,38 +2,46 @@
 package org.openstreetmap.josm.gui.layer.gpx;
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.Collections;
+import java.util.List;
 
 import org.awaitility.Awaitility;
-import org.junit.Rule;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.actions.MergeLayerActionTest.MergeLayerExtendedDialogMocker;
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.layer.GpxLayerTest;
 import org.openstreetmap.josm.gui.layer.TMSLayer;
 import org.openstreetmap.josm.gui.layer.gpx.DownloadWmsAlongTrackAction.PrecacheWmsTask;
-import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
-import org.openstreetmap.josm.testutils.TileSourceRule;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.BasicWiremock;
+import org.openstreetmap.josm.testutils.annotations.FakeImagery;
+import org.openstreetmap.josm.testutils.annotations.fake_imagery.ConstSource;
 import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
 
+import com.github.tomakehurst.wiremock.WireMockServer;
+
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link DownloadWmsAlongTrackAction} class.
  */
-public class DownloadWmsAlongTrackActionTest {
+@BasicPreferences
+@FakeImagery
+class DownloadWmsAlongTrackActionTest {
 
     /**
      * Setup test.
      */
-    @Rule
+    @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
     public JOSMTestRules test = new JOSMTestRules().main().projection().fakeImagery().timeout(20000);
 
@@ -41,7 +49,7 @@ public class DownloadWmsAlongTrackActionTest {
      * Test action without layer.
      */
     @Test
-    public void testNoLayer() {
+    void testNoLayer() {
         TestUtils.assumeWorkingJMockit();
         final JOptionPaneSimpleMocker jopsMocker = new JOptionPaneSimpleMocker(
             Collections.singletonMap("There are no imagery layers.", 0)
@@ -60,15 +68,14 @@ public class DownloadWmsAlongTrackActionTest {
      * @throws Exception if an error occurs
      */
     @Test
-    public void testTMSLayer() throws Exception {
+    void testTMSLayer(@BasicWiremock final WireMockServer wireMockServer,
+            @FakeImagery final List<ConstSource> constSources) throws Exception {
         TestUtils.assumeWorkingJMockit();
         final MergeLayerExtendedDialogMocker edMocker = new MergeLayerExtendedDialogMocker();
         edMocker.getMockResultMap().put("Please select the imagery layer.", "Download");
 
-        final TileSourceRule tileSourceRule = this.test.getTileSourceRule();
-
         final TMSLayer layer = new TMSLayer(
-            tileSourceRule.getSourcesList().get(0).getImageryInfo(tileSourceRule.port())
+                constSources.get(0).getImageryInfo(wireMockServer)
         );
         try {
             MainApplication.getLayerManager().addLayer(layer);
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelperTest.java b/test/unit/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelperTest.java
index 839fbdd7dc..72a9f32abb 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelperTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelperTest.java
@@ -11,31 +11,21 @@ import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
-import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.gui.layer.gpx.GpxDrawHelper.ColorMode;
 import org.openstreetmap.josm.io.GpxReaderTest;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.ColorHelper;
 import org.xml.sax.SAXException;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
 /**
  * Unit tests of {@link GpxDrawHelper} class.
  */
+@BasicPreferences
 class GpxDrawHelperTest {
-
-    /**
-     * Setup test.
-     */
-    @RegisterExtension
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules();
-
     /**
      * Non-regression test for ticket <a href="https://josm.openstreetmap.de/ticket/12312">#12312</a>.
      * @throws IOException if any I/O error occurs
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarkerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarkerTest.java
index ea04e500e3..7d7b0edc91 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarkerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/AudioMarkerTest.java
@@ -12,10 +12,12 @@ import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.data.gpx.WayPoint;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link AudioMarker} class.
  */
+@BasicPreferences
 class AudioMarkerTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/ImageMarkerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/ImageMarkerTest.java
index 0df5962e39..4cc210bf3d 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/ImageMarkerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/ImageMarkerTest.java
@@ -6,26 +6,17 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import java.net.MalformedURLException;
 import java.net.URL;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.data.gpx.WayPoint;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link ImageMarker} class.
  */
+@BasicPreferences
 class ImageMarkerTest {
-
-    /**
-     * Setup tests
-     */
-    @BeforeAll
-    public static void setUpBeforeClass() {
-        JOSMFixture.createUnitTestFixture().init();
-    }
-
     /**
      * Unit test of {@link ImageMarker#ImageMarker}.
      * @throws MalformedURLException never
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayerTest.java
index c6931ec939..bba9167890 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/MarkerLayerTest.java
@@ -22,12 +22,14 @@ import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link MarkerLayer} class.
  */
+@BasicPreferences
 class MarkerLayerTest {
 
     /**
@@ -35,7 +37,7 @@ class MarkerLayerTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().main().preferences().projection();
+    public JOSMTestRules test = new JOSMTestRules().main().projection();
 
     /**
      * Setup tests
diff --git a/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/WebMarkerTest.java b/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/WebMarkerTest.java
index 21ce309d49..5acc1dbb4f 100644
--- a/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/WebMarkerTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/layer/markerlayer/WebMarkerTest.java
@@ -12,6 +12,7 @@ import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.gpx.GpxData;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.PlatformManager;
 import org.openstreetmap.josm.tools.PlatformHook;
 
@@ -24,6 +25,7 @@ import mockit.Mocked;
 /**
  * Unit tests of {@link WebMarker} class.
  */
+@BasicPreferences
 class WebMarkerTest {
 
     /**
@@ -31,7 +33,7 @@ class WebMarkerTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().https();
+    public JOSMTestRules test = new JOSMTestRules().https();
 
     /**
      * Unit test of {@link WebMarker#WebMarker}.
diff --git a/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/AllMapCSSTests.java b/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/AllMapCSSTests.java
index bbb7fe4ea1..6d040e3089 100644
--- a/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/AllMapCSSTests.java
+++ b/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/AllMapCSSTests.java
@@ -1,14 +1,12 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.mappaint.mapcss;
 
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import org.junit.platform.suite.api.SelectClasses;
 
 /**
  * All MapCSS tests.
  */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
+@SelectClasses({
     KeyValueConditionTest.class,
     ParsingLinkSelectorTest.class,
     KeyConditionTest.class,
diff --git a/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTestIT.java b/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTestIT.java
index 6db613fbe7..5561a0a99c 100644
--- a/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTestIT.java
+++ b/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTestIT.java
@@ -8,10 +8,12 @@ import org.openstreetmap.josm.gui.mappaint.mapcss.parsergen.MapCSSParser;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.IntegrationTest;
 
 /**
  * Integration tests of {@link MapCSSParser}.
  */
+@IntegrationTest
 class MapCSSParserTestIT {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/advanced/ExportProfileActionTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/advanced/ExportProfileActionTest.java
index f9be2da17a..dc36fb24e2 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/advanced/ExportProfileActionTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/advanced/ExportProfileActionTest.java
@@ -10,6 +10,7 @@ import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -17,13 +18,14 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests of {@link ExportProfileAction} class.
  */
+@BasicPreferences
 class ExportProfileActionTest {
     /**
      * Setup tests
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().assertionsInEDT();
+    public JOSMTestRules test = new JOSMTestRules().assertionsInEDT();
 
     /**
      * Unit test of {@link ExportProfileAction#actionPerformed}.
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/advanced/PreferencesTableTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/advanced/PreferencesTableTest.java
index 2264a2fe05..cd6c540c9d 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/advanced/PreferencesTableTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/advanced/PreferencesTableTest.java
@@ -17,6 +17,7 @@ import org.openstreetmap.josm.gui.ExtendedDialog;
 import org.openstreetmap.josm.gui.preferences.advanced.PreferencesTable.AllSettingsTableModel;
 import org.openstreetmap.josm.spi.preferences.StringSetting;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.testutils.mockers.ExtendedDialogMocker;
 import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
 
@@ -25,13 +26,14 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests of {@link PreferencesTable} class.
  */
+@BasicPreferences
 class PreferencesTableTest {
     /**
      * Setup tests
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().assertionsInEDT();
+    public JOSMTestRules test = new JOSMTestRules().assertionsInEDT();
 
     private static PrefEntry newPrefEntry(String value) {
         StringSetting val = new StringSetting(value);
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/display/ColorPreferenceTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/display/ColorPreferenceTest.java
index 3cc1540cb4..6627aa4bb5 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/display/ColorPreferenceTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/display/ColorPreferenceTest.java
@@ -3,24 +3,15 @@ package org.openstreetmap.josm.gui.preferences.display;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link ColorPreference} class.
  */
+@BasicPreferences
 class ColorPreferenceTest {
-
-    /**
-     * Setup test.
-     */
-    @BeforeAll
-    public static void setUpBeforeClass() {
-        JOSMFixture.createUnitTestFixture().init();
-    }
-
     /**
      * Unit test of {@link ColorPreference#ColorPreference}.
      */
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/display/DisplayPreferenceTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/display/DisplayPreferenceTest.java
index 7d95ab5400..eefb29741c 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/display/DisplayPreferenceTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/display/DisplayPreferenceTest.java
@@ -3,24 +3,15 @@ package org.openstreetmap.josm.gui.preferences.display;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link DisplayPreference} class.
  */
+@BasicPreferences
 class DisplayPreferenceTest {
-
-    /**
-     * Setup test.
-     */
-    @BeforeAll
-    public static void setUpBeforeClass() {
-        JOSMFixture.createUnitTestFixture().init();
-    }
-
     /**
      * Unit test of {@link DisplayPreference#DisplayPreference}.
      */
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/display/DrawingPreferenceTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/display/DrawingPreferenceTest.java
index c8036c2d31..b882415357 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/display/DrawingPreferenceTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/display/DrawingPreferenceTest.java
@@ -3,24 +3,16 @@ package org.openstreetmap.josm.gui.preferences.display;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link DrawingPreference} class.
  */
+@BasicPreferences
 class DrawingPreferenceTest {
 
-    /**
-     * Setup test.
-     */
-    @BeforeAll
-    public static void setUpBeforeClass() {
-        JOSMFixture.createUnitTestFixture().init();
-    }
-
     /**
      * Unit test of {@link DrawingPreference#DrawingPreference}.
      */
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/display/GPXPreferenceTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/display/GPXPreferenceTest.java
index 7346bb118c..4c1fa12965 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/display/GPXPreferenceTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/display/GPXPreferenceTest.java
@@ -3,24 +3,15 @@ package org.openstreetmap.josm.gui.preferences.display;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link GPXPreference} class.
  */
+@BasicPreferences
 class GPXPreferenceTest {
-
-    /**
-     * Setup test.
-     */
-    @BeforeAll
-    public static void setUpBeforeClass() {
-        JOSMFixture.createUnitTestFixture().init();
-    }
-
     /**
      * Unit test of {@link GPXPreference.Factory}.
      */
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/display/LafPreferenceTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/display/LafPreferenceTest.java
index bb0e1e37f7..16145335a5 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/display/LafPreferenceTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/display/LafPreferenceTest.java
@@ -3,24 +3,15 @@ package org.openstreetmap.josm.gui.preferences.display;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link LafPreference} class.
  */
+@BasicPreferences
 class LafPreferenceTest {
-
-    /**
-     * Setup test.
-     */
-    @BeforeAll
-    public static void setUpBeforeClass() {
-        JOSMFixture.createUnitTestFixture().init();
-    }
-
     /**
      * Unit test of {@link LafPreference#LafPreference}.
      */
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/display/LanguagePreferenceTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/display/LanguagePreferenceTest.java
index f1ff6df7b2..8844d1856e 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/display/LanguagePreferenceTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/display/LanguagePreferenceTest.java
@@ -3,24 +3,15 @@ package org.openstreetmap.josm.gui.preferences.display;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link LanguagePreference} class.
  */
+@BasicPreferences
 class LanguagePreferenceTest {
-
-    /**
-     * Setup test.
-     */
-    @BeforeAll
-    public static void setUpBeforeClass() {
-        JOSMFixture.createUnitTestFixture().init();
-    }
-
     /**
      * Unit test of {@link LanguagePreference#LanguagePreference}.
      */
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreferenceTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreferenceTest.java
index fe01b7e3b6..d1467f6d89 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreferenceTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreferenceTest.java
@@ -12,12 +12,14 @@ import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link ImageryPreference} class.
  */
+@BasicPreferences
 class ImageryPreferenceTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreferenceTestIT.java b/test/unit/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreferenceTestIT.java
index e667e2310b..6d2d350108 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreferenceTestIT.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/imagery/ImageryPreferenceTestIT.java
@@ -65,6 +65,7 @@ import org.openstreetmap.josm.data.projection.Projections;
 import org.openstreetmap.josm.io.imagery.ApiKeyProvider;
 import org.openstreetmap.josm.io.imagery.WMSImagery.WMSGetCapabilitiesException;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.IntegrationTest;
 import org.openstreetmap.josm.tools.HttpClient;
 import org.openstreetmap.josm.tools.HttpClient.Response;
 import org.openstreetmap.josm.tools.Logging;
@@ -75,6 +76,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Integration tests of {@link ImageryPreference} class.
  */
+@IntegrationTest
 public class ImageryPreferenceTestIT {
 
     private static final String ERROR_SEP = " -> ";
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/map/BackupPreferenceTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/map/BackupPreferenceTest.java
index 12ddd6c475..2f54b22edc 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/map/BackupPreferenceTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/map/BackupPreferenceTest.java
@@ -3,24 +3,15 @@ package org.openstreetmap.josm.gui.preferences.map;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link BackupPreference} class.
  */
+@BasicPreferences
 class BackupPreferenceTest {
-
-    /**
-     * Setup test.
-     */
-    @BeforeAll
-    public static void setUpBeforeClass() {
-        JOSMFixture.createUnitTestFixture().init();
-    }
-
     /**
      * Unit test of {@link BackupPreference#BackupPreference}.
      */
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/map/MapPaintPreferenceTestIT.java b/test/unit/org/openstreetmap/josm/gui/preferences/map/MapPaintPreferenceTestIT.java
index e3e668c0a7..913f2a0497 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/map/MapPaintPreferenceTestIT.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/map/MapPaintPreferenceTestIT.java
@@ -25,6 +25,7 @@ import org.openstreetmap.josm.gui.preferences.AbstractExtendedSourceEntryTestCas
 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSRule;
 import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.IntegrationTest;
 import org.openstreetmap.josm.tools.ImageProvider;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -32,6 +33,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Integration tests of {@link MapPaintPreference} class.
  */
+@IntegrationTest
 class MapPaintPreferenceTestIT extends AbstractExtendedSourceEntryTestCase {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreferenceTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreferenceTest.java
index 74bdb1d8c5..d341635d41 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreferenceTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreferenceTest.java
@@ -3,24 +3,15 @@ package org.openstreetmap.josm.gui.preferences.map;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link TaggingPresetPreference} class.
  */
+@BasicPreferences
 class TaggingPresetPreferenceTest {
-
-    /**
-     * Setup test.
-     */
-    @BeforeAll
-    public static void setUpBeforeClass() {
-        JOSMFixture.createUnitTestFixture().init();
-    }
-
     /**
      * Unit test of {@link TaggingPresetPreference#TaggingPresetPreference}.
      */
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreferenceTestIT.java b/test/unit/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreferenceTestIT.java
index 3e714bd3c8..871524deb7 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreferenceTestIT.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/map/TaggingPresetPreferenceTestIT.java
@@ -14,8 +14,10 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Timeout;
 import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
@@ -28,6 +30,8 @@ import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetsTest;
 import org.openstreetmap.josm.gui.tagging.presets.items.Link;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.IntegrationTest;
 import org.openstreetmap.josm.tools.HttpClient;
 import org.openstreetmap.josm.tools.HttpClient.Response;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -39,6 +43,9 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Integration tests of {@link TaggingPresetPreference} class.
  */
+@IntegrationTest
+@BasicPreferences
+@Timeout(value = 20, unit = TimeUnit.MINUTES)
 class TaggingPresetPreferenceTestIT extends AbstractExtendedSourceEntryTestCase {
 
     /**
@@ -46,7 +53,7 @@ class TaggingPresetPreferenceTestIT extends AbstractExtendedSourceEntryTestCase
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public static JOSMTestRules test = new JOSMTestRules().https().timeout(10000*120).parameters();
+    public static JOSMTestRules test = new JOSMTestRules().https().parameters();
 
     /**
      * Setup test
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferenceHighLevelTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferenceHighLevelTest.java
index 1bdab05056..0df7137c36 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferenceHighLevelTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferenceHighLevelTest.java
@@ -1,11 +1,10 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.preferences.plugin;
 
-import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
-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.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.awt.Component;
 import java.io.File;
@@ -18,11 +17,15 @@ import java.util.stream.Collectors;
 
 import javax.swing.JOptionPane;
 
+import com.github.tomakehurst.wiremock.WireMockServer;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import mockit.MockUp;
 import org.awaitility.Awaitility;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
@@ -33,41 +36,37 @@ import org.openstreetmap.josm.plugins.PluginProxy;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 import org.openstreetmap.josm.testutils.PluginServer;
+import org.openstreetmap.josm.testutils.annotations.AssumeRevision;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.BasicWiremock;
 import org.openstreetmap.josm.testutils.mockers.HelpAwareOptionPaneMocker;
 import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
 
-import com.github.tomakehurst.wiremock.client.WireMock;
-import com.github.tomakehurst.wiremock.junit.WireMockRule;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import mockit.MockUp;
-
 /**
  * Higher level tests of {@link PluginPreference} class.
  */
-public class PluginPreferenceHighLevelTest {
+@AssumeRevision("Revision: 10000\n")
+@BasicPreferences(true)
+@BasicWiremock
+class PluginPreferenceHighLevelTest {
     /**
      * Setup test.
      */
-    @Rule
+    @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().assumeRevision(
-        "Revision: 10000\n"
-    ).preferences().main().assertionsInEDT();
+    public JOSMTestRules test = new JOSMTestRules().main().assertionsInEDT();
 
     /**
      * Plugin server mock.
      */
-    @Rule
-    public WireMockRule pluginServerRule = new WireMockRule(
-        options().dynamicPort().usingFilesUnderDirectory(TestUtils.getTestDataRoot())
-    );
+    @BasicWiremock
+    public WireMockServer pluginServerRule;
 
     /**
      * Setup test.
      * @throws ReflectiveOperationException never
      */
-    @Before
+    @BeforeEach
     public void setUp() throws ReflectiveOperationException {
 
         // some other tests actually go ahead and load plugins (notably at time of writing,
@@ -106,7 +105,7 @@ public class PluginPreferenceHighLevelTest {
      * Tear down.
      * @throws ReflectiveOperationException never
      */
-    @After
+    @AfterEach
     public void tearDown() throws ReflectiveOperationException {
         // restore actual PluginHandler#pluginList
         @SuppressWarnings("unchecked")
@@ -135,7 +134,7 @@ public class PluginPreferenceHighLevelTest {
      * @throws Exception never
      */
     @Test
-    public void testInstallWithoutUpdate() throws Exception {
+    void testInstallWithoutUpdate() throws Exception {
         final PluginServer pluginServer = new PluginServer(
             new PluginServer.RemotePlugin(this.referenceDummyJarNew),
             new PluginServer.RemotePlugin(this.referenceBazJarOld),
@@ -169,7 +168,7 @@ public class PluginPreferenceHighLevelTest {
         Awaitility.await().atMost(2000, MILLISECONDS).until(() -> Config.getPref().getInt("pluginmanager.version", 999) != 999);
 
         this.pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
-        WireMock.resetAllRequests();
+        this.pluginServerRule.resetRequests();
 
         final PluginPreferencesModel model = (PluginPreferencesModel) TestUtils.getPrivateField(
             tabbedPane.getPluginPreference(),
@@ -256,7 +255,7 @@ public class PluginPreferenceHighLevelTest {
      * @throws Exception never
      */
     @Test
-    public void testDisablePluginWithUpdatesAvailable() throws Exception {
+    void testDisablePluginWithUpdatesAvailable() throws Exception {
         final PluginServer pluginServer = new PluginServer(
             new PluginServer.RemotePlugin(this.referenceDummyJarNew),
             new PluginServer.RemotePlugin(this.referenceBazJarNew),
@@ -289,7 +288,7 @@ public class PluginPreferenceHighLevelTest {
         Awaitility.await().atMost(2000, MILLISECONDS).until(() -> Config.getPref().getInt("pluginmanager.version", 999) != 999);
 
         this.pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
-        WireMock.resetAllRequests();
+        this.pluginServerRule.resetRequests();
 
         final PluginPreferencesModel model = (PluginPreferencesModel) TestUtils.getPrivateField(
             tabbedPane.getPluginPreference(),
@@ -378,7 +377,7 @@ public class PluginPreferenceHighLevelTest {
      * @throws Exception never
      */
     @Test
-    public void testUpdateOnlySelectedPlugin() throws Exception {
+    void testUpdateOnlySelectedPlugin() throws Exception {
         TestUtils.assumeWorkingJMockit();
         final PluginServer pluginServer = new PluginServer(
             new PluginServer.RemotePlugin(this.referenceDummyJarNew),
@@ -406,7 +405,7 @@ public class PluginPreferenceHighLevelTest {
         TestUtils.syncEDTAndWorkerThreads();
 
         this.pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
-        WireMock.resetAllRequests();
+        this.pluginServerRule.resetRequests();
 
         final PluginPreferencesModel model = (PluginPreferencesModel) TestUtils.getPrivateField(
             tabbedPane.getPluginPreference(),
@@ -485,7 +484,7 @@ public class PluginPreferenceHighLevelTest {
         this.pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugin/dummy_plugin.v31772.jar")));
         // baz_plugin has not
         this.pluginServerRule.verify(0, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugin/baz_plugin.v7.jar")));
-        WireMock.resetAllRequests();
+        this.pluginServerRule.resetRequests();
 
         // pluginmanager.version has been set to the current version
         // questionably correct
@@ -566,7 +565,7 @@ public class PluginPreferenceHighLevelTest {
      * @throws Exception never
      */
     @Test
-    public void testUpdateWithNoAvailableUpdates() throws Exception {
+    void testUpdateWithNoAvailableUpdates() throws Exception {
         TestUtils.assumeWorkingJMockit();
         final PluginServer pluginServer = new PluginServer(
             new PluginServer.RemotePlugin(this.referenceDummyJarOld),
@@ -600,7 +599,7 @@ public class PluginPreferenceHighLevelTest {
         TestUtils.syncEDTAndWorkerThreads();
 
         this.pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
-        WireMock.resetAllRequests();
+        this.pluginServerRule.resetRequests();
 
         final PluginPreferencesModel model = (PluginPreferencesModel) TestUtils.getPrivateField(
             tabbedPane.getPluginPreference(),
@@ -656,7 +655,7 @@ public class PluginPreferenceHighLevelTest {
         this.pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
         // that should have been the only request to our PluginServer
         assertEquals(1, this.pluginServerRule.getAllServeEvents().size());
-        WireMock.resetAllRequests();
+        this.pluginServerRule.resetRequests();
 
         // pluginmanager.version has been set to the current version
         assertEquals(10000, Config.getPref().getInt("pluginmanager.version", 111));
@@ -705,7 +704,7 @@ public class PluginPreferenceHighLevelTest {
      * @throws Exception never
      */
     @Test
-    public void testInstallWithoutRestartRequired() throws Exception {
+    void testInstallWithoutRestartRequired() throws Exception {
         TestUtils.assumeWorkingJMockit();
         final boolean[] loadPluginsCalled = new boolean[] {false};
         new MockUp<PluginHandler>() {
@@ -749,7 +748,7 @@ public class PluginPreferenceHighLevelTest {
         TestUtils.syncEDTAndWorkerThreads();
 
         this.pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
-        WireMock.resetAllRequests();
+        this.pluginServerRule.resetRequests();
 
         final PluginPreferencesModel model = (PluginPreferencesModel) TestUtils.getPrivateField(
             tabbedPane.getPluginPreference(),
@@ -825,9 +824,9 @@ public class PluginPreferenceHighLevelTest {
      * preventing us from using the latest version
      * @throws Exception on failure
      */
-    @JOSMTestRules.OverrideAssumeRevision("Revision: 7000\n")
+    @AssumeRevision("Revision: 7000\n")
     @Test
-    public void testInstallMultiVersion() throws Exception {
+    void testInstallMultiVersion() throws Exception {
         TestUtils.assumeWorkingJMockit();
 
         final String bazOldServePath = "/baz/old.jar";
@@ -870,7 +869,7 @@ public class PluginPreferenceHighLevelTest {
         TestUtils.syncEDTAndWorkerThreads();
 
         this.pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
-        WireMock.resetAllRequests();
+        this.pluginServerRule.resetRequests();
 
         final PluginPreferencesModel model = (PluginPreferencesModel) TestUtils.getPrivateField(
             tabbedPane.getPluginPreference(),
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferenceTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferenceTest.java
index fc602eae74..d0d2e5a817 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferenceTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/plugin/PluginPreferenceTest.java
@@ -18,6 +18,7 @@ import org.openstreetmap.josm.plugins.PluginDownloadTask;
 import org.openstreetmap.josm.plugins.PluginException;
 import org.openstreetmap.josm.plugins.PluginInformation;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.testutils.mockers.HelpAwareOptionPaneMocker;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -25,13 +26,14 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests of {@link PluginPreference} class.
  */
+@BasicPreferences
 public class PluginPreferenceTest {
     /**
      * Setup test.
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().assertionsInEDT();
+    public JOSMTestRules test = new JOSMTestRules().assertionsInEDT();
 
     /**
      * Unit test of {@link PluginPreference#PluginPreference}.
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/projection/ProjectionPreferenceTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/projection/ProjectionPreferenceTest.java
index 3ebd2f214a..c5762b1904 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/projection/ProjectionPreferenceTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/projection/ProjectionPreferenceTest.java
@@ -3,24 +3,15 @@ package org.openstreetmap.josm.gui.preferences.projection;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link ProjectionPreference} class.
  */
+@BasicPreferences
 class ProjectionPreferenceTest {
-
-    /**
-     * Setup test.
-     */
-    @BeforeAll
-    public static void setUpBeforeClass() {
-        JOSMFixture.createUnitTestFixture().init();
-    }
-
     /**
      * Unit test of {@link ProjectionPreference#ProjectionPreference}.
      */
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/remotecontrol/RemoteControlPreferenceTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/remotecontrol/RemoteControlPreferenceTest.java
index f884389305..206ff41cc3 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/remotecontrol/RemoteControlPreferenceTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/remotecontrol/RemoteControlPreferenceTest.java
@@ -3,24 +3,15 @@ package org.openstreetmap.josm.gui.preferences.remotecontrol;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link RemoteControlPreference} class.
  */
+@BasicPreferences
 class RemoteControlPreferenceTest {
-
-    /**
-     * Setup test.
-     */
-    @BeforeAll
-    public static void setUpBeforeClass() {
-        JOSMFixture.createUnitTestFixture().init();
-    }
-
     /**
      * Unit test of {@link RemoteControlPreference#RemoteControlPreference}.
      */
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/validator/ValidatorPreferenceTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/validator/ValidatorPreferenceTest.java
index 735689b2a5..0206638a5c 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/validator/ValidatorPreferenceTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/validator/ValidatorPreferenceTest.java
@@ -3,24 +3,15 @@ package org.openstreetmap.josm.gui.preferences.validator;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link ValidatorPreference} class.
  */
+@BasicPreferences
 class ValidatorPreferenceTest {
-
-    /**
-     * Setup test.
-     */
-    @BeforeAll
-    public static void setUpBeforeClass() {
-        JOSMFixture.createUnitTestFixture().init();
-    }
-
     /**
      * Unit test of {@link ValidatorPreference#ValidatorPreference}.
      */
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/validator/ValidatorTagCheckerRulesPreferenceTestIT.java b/test/unit/org/openstreetmap/josm/gui/preferences/validator/ValidatorTagCheckerRulesPreferenceTestIT.java
index 677cc11049..fcf25a975c 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/validator/ValidatorTagCheckerRulesPreferenceTestIT.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/validator/ValidatorTagCheckerRulesPreferenceTestIT.java
@@ -26,10 +26,12 @@ import org.openstreetmap.josm.gui.preferences.AbstractExtendedSourceEntryTestCas
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.IntegrationTest;
 
 /**
  * Integration tests of {@link ValidatorTagCheckerRulesPreference} class.
  */
+@IntegrationTest
 class ValidatorTagCheckerRulesPreferenceTestIT extends AbstractExtendedSourceEntryTestCase {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/preferences/validator/ValidatorTestsPreferenceTest.java b/test/unit/org/openstreetmap/josm/gui/preferences/validator/ValidatorTestsPreferenceTest.java
index 3c03344059..4538f3c5ba 100644
--- a/test/unit/org/openstreetmap/josm/gui/preferences/validator/ValidatorTestsPreferenceTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/preferences/validator/ValidatorTestsPreferenceTest.java
@@ -3,24 +3,15 @@ package org.openstreetmap.josm.gui.preferences.validator;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.gui.preferences.PreferencesTestUtils;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link ValidatorTestsPreference} class.
  */
+@BasicPreferences
 class ValidatorTestsPreferenceTest {
-
-    /**
-     * Setup test.
-     */
-    @BeforeAll
-    public static void setUpBeforeClass() {
-        JOSMFixture.createUnitTestFixture().init();
-    }
-
     /**
      * Unit test of {@link ValidatorTestsPreference#ValidatorTestsPreference}.
      */
diff --git a/test/unit/org/openstreetmap/josm/gui/tagging/presets/PresetClassificationsTest.java b/test/unit/org/openstreetmap/josm/gui/tagging/presets/PresetClassificationsTest.java
index eba467c4f4..d912fd9ff2 100644
--- a/test/unit/org/openstreetmap/josm/gui/tagging/presets/PresetClassificationsTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/tagging/presets/PresetClassificationsTest.java
@@ -13,18 +13,19 @@ import java.util.stream.Collectors;
 
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.JOSMFixture;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetSelector.PresetClassification;
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetSelector.PresetClassifications;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.xml.sax.SAXException;
 
 /**
  * Unit tests of {@link PresetClassifications} class.
  */
+@BasicPreferences
 class PresetClassificationsTest {
 
     static final PresetClassifications classifications = new PresetClassifications();
@@ -36,7 +37,6 @@ class PresetClassificationsTest {
      */
     @BeforeAll
     public static void setUp() throws IOException, SAXException {
-        JOSMFixture.createUnitTestFixture().init();
         final Collection<TaggingPreset> presets = TaggingPresetReader.readAll("resource://data/defaultpresets.xml", true);
         classifications.loadPresets(presets);
     }
diff --git a/test/unit/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReaderTest.java b/test/unit/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReaderTest.java
index c4cf522762..8f42792ba1 100644
--- a/test/unit/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReaderTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetReaderTest.java
@@ -12,29 +12,18 @@ import java.util.Collection;
 import java.util.List;
 import java.util.stream.Collectors;
 
-import org.junit.Assert;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.gui.tagging.presets.items.Check;
 import org.openstreetmap.josm.gui.tagging.presets.items.Key;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.xml.sax.SAXException;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
 /**
  * Unit tests of {@link TaggingPresetReader} class.
  */
+@BasicPreferences
 class TaggingPresetReaderTest {
-
-    /**
-     * Setup rule
-     */
-    @RegisterExtension
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules();
-
     /**
      * #8954 - last checkbox in the preset is not added
      * @throws SAXException if any XML error occurs
@@ -44,11 +33,11 @@ class TaggingPresetReaderTest {
     void testTicket8954() throws SAXException, IOException {
         String presetfile = TestUtils.getRegressionDataFile(8954, "preset.xml");
         final Collection<TaggingPreset> presets = TaggingPresetReader.readAll(presetfile, false);
-        Assert.assertEquals("Number of preset items", 1, presets.size());
+        assertEquals(1, presets.size(), "Number of preset items");
         final TaggingPreset preset = presets.iterator().next();
-        Assert.assertEquals("Number of entries", 1, preset.data.size());
+        assertEquals(1, preset.data.size(), "Number of entries");
         final TaggingPresetItem item = preset.data.get(0);
-        Assert.assertTrue("Entry is not checkbox", item instanceof Check);
+        assertTrue(item instanceof Check, "Entry is not checkbox");
     }
 
     /**
@@ -92,6 +81,6 @@ class TaggingPresetReaderTest {
     void testReadDefaulPresets() throws SAXException, IOException {
         String presetfile = "resource://data/defaultpresets.xml";
         final Collection<TaggingPreset> presets = TaggingPresetReader.readAll(presetfile, true);
-        Assert.assertTrue("Default presets are empty", presets.size() > 0);
+        assertTrue(presets.size() > 0, "Default presets are empty");
     }
 }
diff --git a/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/CheckTest.java b/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/CheckTest.java
index 8fae5a60d0..5e6e30ed4b 100644
--- a/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/CheckTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/CheckTest.java
@@ -10,12 +10,14 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetItemGuiSupport;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link Check} class.
  */
+@BasicPreferences
 class CheckTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/ComboTest.java b/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/ComboTest.java
index feabfa1bea..689503a9fa 100644
--- a/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/ComboTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/ComboTest.java
@@ -14,12 +14,14 @@ import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetItemGuiSupport;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link Combo} class.
  */
+@BasicPreferences
 class ComboTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/PresetLinkTest.java b/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/PresetLinkTest.java
index 66c151189d..93afd59cf3 100644
--- a/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/PresetLinkTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/PresetLinkTest.java
@@ -11,12 +11,14 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetItemGuiSupport;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link PresetLink} class.
  */
+@BasicPreferences
 class PresetLinkTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/TextTest.java b/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/TextTest.java
index 6979cad768..64d201a277 100644
--- a/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/TextTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/tagging/presets/items/TextTest.java
@@ -10,12 +10,14 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetItemGuiSupport;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link Text} class.
  */
+@BasicPreferences
 class TextTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/io/CertificateAmendmentTestIT.java b/test/unit/org/openstreetmap/josm/io/CertificateAmendmentTestIT.java
index 90d640e298..16b4107e32 100644
--- a/test/unit/org/openstreetmap/josm/io/CertificateAmendmentTestIT.java
+++ b/test/unit/org/openstreetmap/josm/io/CertificateAmendmentTestIT.java
@@ -19,10 +19,12 @@ import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.IntegrationTest;
 
 /**
  * Integration tests of {@link CertificateAmendment} class.
  */
+@IntegrationTest
 class CertificateAmendmentTestIT {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/io/NameFinderTest.java b/test/unit/org/openstreetmap/josm/io/NameFinderTest.java
index 8a3f0569fa..dee6b497ca 100644
--- a/test/unit/org/openstreetmap/josm/io/NameFinderTest.java
+++ b/test/unit/org/openstreetmap/josm/io/NameFinderTest.java
@@ -8,12 +8,10 @@ import java.util.Arrays;
 import java.util.stream.Collectors;
 
 import org.junit.jupiter.api.Test;
-import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link NameFinder} class.
  */
-@BasicPreferences
 class NameFinderTest {
 
     // CHECKSTYLE.OFF: LineLength
diff --git a/test/unit/org/openstreetmap/josm/io/NetworkManagerTest.java b/test/unit/org/openstreetmap/josm/io/NetworkManagerTest.java
index 22ddf1a670..dc722476f1 100644
--- a/test/unit/org/openstreetmap/josm/io/NetworkManagerTest.java
+++ b/test/unit/org/openstreetmap/josm/io/NetworkManagerTest.java
@@ -12,12 +12,14 @@ import java.util.Map;
 import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link NetworkManager} class.
  */
+@BasicPreferences
 class NetworkManagerTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/io/ValidatorErrorWriterTest.java b/test/unit/org/openstreetmap/josm/io/ValidatorErrorWriterTest.java
index 0385968622..c90799bd47 100644
--- a/test/unit/org/openstreetmap/josm/io/ValidatorErrorWriterTest.java
+++ b/test/unit/org/openstreetmap/josm/io/ValidatorErrorWriterTest.java
@@ -12,28 +12,18 @@ import java.util.Collections;
 import java.util.Locale;
 
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.validation.Severity;
 import org.openstreetmap.josm.data.validation.TestError;
 import org.openstreetmap.josm.data.validation.tests.RightAngleBuildingTest;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 /**
  * Unit tests of {@link ValidatorErrorWriter}
  */
+@BasicPreferences
 class ValidatorErrorWriterTest {
-
-    /**
-     * Setup rule
-     */
-    @RegisterExtension
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences();
-
     @Test
     void testEmpty() throws IOException {
         doTest(Collections.emptyList(), "");
diff --git a/test/unit/org/openstreetmap/josm/io/remotecontrol/RemoteControlTest.java b/test/unit/org/openstreetmap/josm/io/remotecontrol/RemoteControlTest.java
index 583ab5f393..c03f1311a7 100644
--- a/test/unit/org/openstreetmap/josm/io/remotecontrol/RemoteControlTest.java
+++ b/test/unit/org/openstreetmap/josm/io/remotecontrol/RemoteControlTest.java
@@ -16,6 +16,7 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.Utils;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -23,6 +24,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests for Remote Control
  */
+@BasicPreferences
 class RemoteControlTest {
 
     private String httpBase;
@@ -32,7 +34,7 @@ class RemoteControlTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().https().assertionsInEDT();
+    public JOSMTestRules test = new JOSMTestRules().https().assertionsInEDT();
 
     /**
      * Starts Remote control before testing requests.
diff --git a/test/unit/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandlerTest.java b/test/unit/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandlerTest.java
index 976134f011..9e09ba66f4 100644
--- a/test/unit/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandlerTest.java
+++ b/test/unit/org/openstreetmap/josm/io/remotecontrol/handler/AddNodeHandlerTest.java
@@ -12,12 +12,14 @@ import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerBadRequestException;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link AddNodeHandler} class.
  */
+@BasicPreferences
 class AddNodeHandlerTest {
     /**
      * Setup test.
diff --git a/test/unit/org/openstreetmap/josm/io/remotecontrol/handler/ImportHandlerTest.java b/test/unit/org/openstreetmap/josm/io/remotecontrol/handler/ImportHandlerTest.java
index 625759f3f6..f81e8c7409 100644
--- a/test/unit/org/openstreetmap/josm/io/remotecontrol/handler/ImportHandlerTest.java
+++ b/test/unit/org/openstreetmap/josm/io/remotecontrol/handler/ImportHandlerTest.java
@@ -14,6 +14,7 @@ import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerBadRequestException;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.Utils;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -21,6 +22,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests of {@link ImportHandler} class.
  */
+@BasicPreferences
 class ImportHandlerTest {
     /**
      * Setup test.
diff --git a/test/unit/org/openstreetmap/josm/io/session/SessionReaderTest.java b/test/unit/org/openstreetmap/josm/io/session/SessionReaderTest.java
index acf5f77170..69158c461a 100644
--- a/test/unit/org/openstreetmap/josm/io/session/SessionReaderTest.java
+++ b/test/unit/org/openstreetmap/josm/io/session/SessionReaderTest.java
@@ -27,12 +27,14 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
 import org.openstreetmap.josm.io.IllegalDataException;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests for Session reading.
  */
+@BasicPreferences
 class SessionReaderTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java b/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java
index 0cce3b77de..3a41c0b374 100644
--- a/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java
+++ b/test/unit/org/openstreetmap/josm/io/session/SessionWriterTest.java
@@ -37,6 +37,7 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.TMSLayer;
 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.MultiMap;
 import org.openstreetmap.josm.tools.Utils;
 
@@ -47,6 +48,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 /**
  * Unit tests for Session writing.
  */
+@BasicPreferences
 class SessionWriterTest {
 
     protected static final class OsmHeadlessJosExporter extends OsmDataSessionExporter {
diff --git a/test/unit/org/openstreetmap/josm/plugins/PluginHandlerJOSMTooOldTest.java b/test/unit/org/openstreetmap/josm/plugins/PluginHandlerJOSMTooOldTest.java
index 5dffde15f8..210261104f 100644
--- a/test/unit/org/openstreetmap/josm/plugins/PluginHandlerJOSMTooOldTest.java
+++ b/test/unit/org/openstreetmap/josm/plugins/PluginHandlerJOSMTooOldTest.java
@@ -1,10 +1,10 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.plugins;
 
-import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
 
 import java.io.File;
 import java.io.IOException;
@@ -17,48 +17,44 @@ import java.util.Comparator;
 import java.util.List;
 import java.util.stream.Collectors;
 
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
+import com.github.tomakehurst.wiremock.WireMockServer;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 import org.openstreetmap.josm.testutils.PluginServer;
+import org.openstreetmap.josm.testutils.annotations.AssumeRevision;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.BasicWiremock;
 import org.openstreetmap.josm.testutils.mockers.ExtendedDialogMocker;
 import org.openstreetmap.josm.testutils.mockers.HelpAwareOptionPaneMocker;
 
-import com.github.tomakehurst.wiremock.client.WireMock;
-import com.github.tomakehurst.wiremock.junit.WireMockRule;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
 /**
  * Test parts of {@link PluginHandler} class when the reported JOSM version is too old for the plugin.
  */
-public class PluginHandlerJOSMTooOldTest {
-    /**
-     * Setup test.
-     */
-    @Rule
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().main().assumeRevision(
-        "Revision: 6000\n"
-    );
+@BasicPreferences(true)
+@BasicWiremock
+@AssumeRevision("Revision: 6000\n")
+class PluginHandlerJOSMTooOldTest {
+    @RegisterExtension
+    @SuppressWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    JOSMTestRules josmTestRules = new JOSMTestRules().main();
 
     /**
      * Plugin server mock.
      */
-    @Rule
-    public WireMockRule pluginServerRule = new WireMockRule(
-        options().dynamicPort().usingFilesUnderDirectory(TestUtils.getTestDataRoot())
-    );
+    @BasicWiremock
+    public WireMockServer pluginServerRule;
 
     /**
      * Setup test.
      */
-    @Before
+    @BeforeEach
     public void setUp() {
         Config.getPref().putInt("pluginmanager.version", 999);
         Config.getPref().put("pluginmanager.lastupdate", "999");
@@ -114,7 +110,7 @@ public class PluginHandlerJOSMTooOldTest {
      * @throws IOException never
      */
     @Test
-    public void testUpdatePluginsDownloadBoth() throws IOException {
+    void testUpdatePluginsDownloadBoth() throws IOException {
         TestUtils.assumeWorkingJMockit();
         final PluginServer pluginServer = new PluginServer(
             new PluginServer.RemotePlugin(this.referenceDummyJarNew),
@@ -176,7 +172,7 @@ public class PluginHandlerJOSMTooOldTest {
      * @throws IOException never
      */
     @Test
-    public void testUpdatePluginsSkipOne() throws IOException {
+    void testUpdatePluginsSkipOne() throws IOException {
         TestUtils.assumeWorkingJMockit();
         final PluginServer pluginServer = new PluginServer(
             new PluginServer.RemotePlugin(this.referenceDummyJarNew),
@@ -248,7 +244,7 @@ public class PluginHandlerJOSMTooOldTest {
      * @throws IOException never
      */
     @Test
-    public void testUpdatePluginsUnexpectedlyJOSMTooOld() throws IOException {
+    void testUpdatePluginsUnexpectedlyJOSMTooOld() throws IOException {
         TestUtils.assumeWorkingJMockit();
         final PluginServer pluginServer = new PluginServer(
             new PluginServer.RemotePlugin(this.referenceDummyJarNew),
@@ -302,8 +298,8 @@ public class PluginHandlerJOSMTooOldTest {
      * @throws IOException never
      */
     @Test
-    @JOSMTestRules.OverrideAssumeRevision("Revision: 7200\n")
-    public void testUpdatePluginsMultiVersionInsufficient() throws IOException {
+    @AssumeRevision("Revision: 7200\n")
+    void testUpdatePluginsMultiVersionInsufficient() throws IOException {
         TestUtils.assumeWorkingJMockit();
 
         final PluginServer pluginServer = new PluginServer(
@@ -342,7 +338,8 @@ public class PluginHandlerJOSMTooOldTest {
         // questionably correct
         TestUtils.assertFileContentsEqual(this.referenceQuxJarNewer, this.targetQuxJar);
 
-        assertEquals(2, WireMock.getAllServeEvents().size());
+        assertEquals(2, this.pluginServerRule.getAllServeEvents().size(), "Requests: " + this.pluginServerRule.getAllServeEvents().stream()
+                .map(serveEvent -> serveEvent.getRequest().getUrl()).collect(Collectors.joining(", ")));
         this.pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
         // questionably correct
         this.pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugin/qux_plugin.v432.jar")));
diff --git a/test/unit/org/openstreetmap/josm/plugins/PluginHandlerMultiVersionTest.java b/test/unit/org/openstreetmap/josm/plugins/PluginHandlerMultiVersionTest.java
index 16d93c571e..0b09ac155e 100644
--- a/test/unit/org/openstreetmap/josm/plugins/PluginHandlerMultiVersionTest.java
+++ b/test/unit/org/openstreetmap/josm/plugins/PluginHandlerMultiVersionTest.java
@@ -1,12 +1,12 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.plugins;
 
-import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
 
 import java.io.File;
+import java.io.IOException;
 import java.nio.file.Files;
 import java.util.Arrays;
 import java.util.Collections;
@@ -16,46 +16,50 @@ import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
+import com.github.tomakehurst.wiremock.WireMockServer;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.apache.commons.io.FileUtils;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.Preferences;
 import org.openstreetmap.josm.gui.MainApplication;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 import org.openstreetmap.josm.testutils.PluginServer;
+import org.openstreetmap.josm.testutils.annotations.AssumeRevision;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.BasicWiremock;
 import org.openstreetmap.josm.testutils.mockers.ExtendedDialogMocker;
 
-import com.github.tomakehurst.wiremock.client.WireMock;
-import com.github.tomakehurst.wiremock.junit.WireMockRule;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
 /**
  * Test parts of {@link PluginHandler} class with plugins that advertise multiple versions for compatibility.
  */
-public class PluginHandlerMultiVersionTest {
+@BasicWiremock
+@BasicPreferences
+@AssumeRevision("7000")
+class PluginHandlerMultiVersionTest {
     /**
      * Setup test.
      */
-    @Rule
+    @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().main();
+    public JOSMTestRules test = new JOSMTestRules().main();
 
     /**
      * Plugin server mock.
      */
-    @Rule
-    public WireMockRule pluginServerRule = new WireMockRule(
-        options().dynamicPort().usingFilesUnderDirectory(TestUtils.getTestDataRoot())
-    );
+    @BasicWiremock
+    WireMockServer pluginServerRule;
 
     /**
      * Setup test.
      */
-    @Before
-    public void setUp() {
+    @BeforeEach
+    void setUp() throws IOException {
         Config.getPref().putInt("pluginmanager.version", 999);
         Config.getPref().put("pluginmanager.lastupdate", "999");
         Config.getPref().putList("pluginmanager.sites",
@@ -71,9 +75,18 @@ public class PluginHandlerMultiVersionTest {
         this.targetBazJarNew = new File(this.pluginDir, "baz_plugin.jar.new");
         this.targetQuxJar = new File(this.pluginDir, "qux_plugin.jar");
         this.targetQuxJarNew = new File(this.pluginDir, "qux_plugin.jar.new");
+        // Clean up the plugin directory
+        if (this.pluginDir.isDirectory()) {
+            FileUtils.cleanDirectory(this.pluginDir);
+        }
         this.pluginDir.mkdirs();
     }
 
+    @AfterEach
+    void afterEach() {
+
+    }
+
     private static final String referencePathQuxJarOld = "plugin/qux_plugin.v345.jar";
     private static final String referencePathQuxJarNewer = "plugin/qux_plugin.v432.jar";
     private static final String referencePathQuxJarNewest = "plugin/qux_plugin.v435.jar";
@@ -93,9 +106,9 @@ public class PluginHandlerMultiVersionTest {
      * but an additional version is listed which *does* support our version
      * @throws Exception on failure
      */
-    @JOSMTestRules.OverrideAssumeRevision("Revision: 7501\n")
+    @AssumeRevision("Revision: 7501\n")
     @Test
-    public void testUpdatePluginsOneMultiVersion() throws Exception {
+    void testUpdatePluginsOneMultiVersion() throws Exception {
         TestUtils.assumeWorkingJMockit();
 
         final String quxNewerServePath = "/qux/newer.jar";
@@ -146,7 +159,7 @@ public class PluginHandlerMultiVersionTest {
         TestUtils.assertFileContentsEqual(this.referenceBazJarOld, this.targetBazJar);
         TestUtils.assertFileContentsEqual(this.referenceQuxJarNewer, this.targetQuxJar);
 
-        assertEquals(2, WireMock.getAllServeEvents().size());
+        assertEquals(2, this.pluginServerRule.getAllServeEvents().size());
         this.pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
         this.pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo(quxNewerServePath)));
 
@@ -160,9 +173,9 @@ public class PluginHandlerMultiVersionTest {
      * we already have, which is still listed.
      * @throws Exception on failure
      */
-    @JOSMTestRules.OverrideAssumeRevision("Revision: 7000\n")
+    @AssumeRevision("Revision: 7000\n")
     @Test
-    public void testUpdatePluginsExistingVersionLatestPossible() throws Exception {
+    void testUpdatePluginsExistingVersionLatestPossible() throws Exception {
         TestUtils.assumeWorkingJMockit();
 
         final Map<String, String> attrOverrides = new HashMap<String, String>() {{
@@ -206,7 +219,7 @@ public class PluginHandlerMultiVersionTest {
         TestUtils.assertFileContentsEqual(this.referenceQuxJarOld, this.targetQuxJar);
 
         // only the plugins list should have been downloaded
-        assertEquals(1, WireMock.getAllServeEvents().size());
+        assertEquals(1, this.pluginServerRule.getAllServeEvents().size());
         this.pluginServerRule.verify(1, WireMock.getRequestedFor(WireMock.urlEqualTo("/plugins")));
 
         assertEquals(7000, Config.getPref().getInt("pluginmanager.version", 111));
diff --git a/test/unit/org/openstreetmap/josm/plugins/PluginHandlerTest.java b/test/unit/org/openstreetmap/josm/plugins/PluginHandlerTest.java
index aeefa91805..875cf24278 100644
--- a/test/unit/org/openstreetmap/josm/plugins/PluginHandlerTest.java
+++ b/test/unit/org/openstreetmap/josm/plugins/PluginHandlerTest.java
@@ -23,6 +23,7 @@ import org.openstreetmap.josm.gui.widgets.JosmTextArea;
 import org.openstreetmap.josm.plugins.PluginHandler.DeprecatedPlugin;
 import org.openstreetmap.josm.plugins.PluginHandler.PluginInformationAction;
 import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.I18n;
 import org.openstreetmap.josm.testutils.mockers.HelpAwareOptionPaneMocker;
 import org.openstreetmap.josm.testutils.mockers.JOptionPaneSimpleMocker;
 
@@ -33,6 +34,7 @@ import org.junit.jupiter.api.Test;
  * Unit tests of {@link PluginHandler} class.
  */
 @BasicPreferences
+@I18n
 class PluginHandlerTest {
     /**
      * Unit test of methods {@link DeprecatedPlugin#equals} and {@link DeprecatedPlugin#hashCode}.
diff --git a/test/unit/org/openstreetmap/josm/plugins/PluginHandlerTestIT.java b/test/unit/org/openstreetmap/josm/plugins/PluginHandlerTestIT.java
index 6e70c9889b..51f80edee0 100644
--- a/test/unit/org/openstreetmap/josm/plugins/PluginHandlerTestIT.java
+++ b/test/unit/org/openstreetmap/josm/plugins/PluginHandlerTestIT.java
@@ -15,13 +15,14 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Timeout;
 import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.data.Preferences;
@@ -34,6 +35,10 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.Main;
+import org.openstreetmap.josm.testutils.annotations.Projection;
+import org.openstreetmap.josm.testutils.annotations.Territories;
 import org.openstreetmap.josm.tools.Destroyable;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.Utils;
@@ -43,6 +48,11 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Integration tests of {@link PluginHandler} class.
  */
+@BasicPreferences
+@Projection
+@Main
+@Territories
+@Timeout(value = 10, unit = TimeUnit.MINUTES)
 public class PluginHandlerTestIT {
 
     private static final List<String> errorsToIgnore = new ArrayList<>();
@@ -51,8 +61,7 @@ public class PluginHandlerTestIT {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public static JOSMTestRules test = new JOSMTestRules().main().projection().preferences().https()
-            .territories().timeout(10 * 60 * 1000);
+    public static JOSMTestRules test = new JOSMTestRules().https();
 
     /**
      * Setup test
@@ -73,7 +82,7 @@ public class PluginHandlerTestIT {
 
         Map<String, Throwable> loadingExceptions = PluginHandler.pluginLoadingExceptions.entrySet().stream()
                 .filter(e -> !(Utils.getRootCause(e.getValue()) instanceof HeadlessException))
-                .collect(Collectors.toMap(e -> e.getKey(), e -> Utils.getRootCause(e.getValue())));
+                .collect(Collectors.toMap(Map.Entry::getKey, e -> Utils.getRootCause(e.getValue())));
 
         List<PluginInformation> loadedPlugins = PluginHandler.getPlugins();
         Map<String, List<String>> invalidManifestEntries = loadedPlugins.stream().filter(pi -> !pi.invalidManifestEntries.isEmpty())
@@ -147,17 +156,17 @@ public class PluginHandlerTestIT {
     private static <T> Map<String, T> filterKnownErrors(Map<String, T> errorMap) {
         return errorMap.entrySet().parallelStream()
                 .filter(entry -> !errorsToIgnore.contains(convertEntryToString(entry)))
-                .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
+                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
     }
 
     private static void debugPrint(Map<String, ?> invalidManifestEntries) {
         System.out.println(invalidManifestEntries.entrySet()
                 .stream()
-                .map(e -> convertEntryToString(e))
+                .map(PluginHandlerTestIT::convertEntryToString)
                 .collect(Collectors.joining(", ")));
     }
 
-    private static String convertEntryToString(Entry<String, ?> entry) {
+    private static String convertEntryToString(Map.Entry<String, ?> entry) {
         return entry.getKey() + "=\"" + entry.getValue() + "\"";
     }
 
diff --git a/test/unit/org/openstreetmap/josm/spi/lifecycle/LifecycleTest.java b/test/unit/org/openstreetmap/josm/spi/lifecycle/LifecycleTest.java
index 9c4fd03875..483ddf1fba 100644
--- a/test/unit/org/openstreetmap/josm/spi/lifecycle/LifecycleTest.java
+++ b/test/unit/org/openstreetmap/josm/spi/lifecycle/LifecycleTest.java
@@ -7,12 +7,14 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.Test;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link Lifecycle} class.
  */
+@BasicPreferences
 class LifecycleTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java b/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java
index b68e571827..27f7959116 100644
--- a/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java
+++ b/test/unit/org/openstreetmap/josm/testutils/JOSMTestRules.java
@@ -6,7 +6,6 @@ import java.awt.GraphicsEnvironment;
 import java.awt.Toolkit;
 import java.awt.Window;
 import java.awt.event.WindowEvent;
-import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -17,7 +16,6 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.lang.reflect.Method;
-import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
 import java.text.MessageFormat;
 import java.util.Arrays;
@@ -26,6 +24,7 @@ import java.util.TimeZone;
 import java.util.logging.Handler;
 import java.util.logging.Level;
 
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import org.awaitility.Awaitility;
 import org.junit.jupiter.api.extension.AfterAllCallback;
 import org.junit.jupiter.api.extension.AfterEachCallback;
@@ -64,6 +63,8 @@ import org.openstreetmap.josm.io.OsmConnection;
 import org.openstreetmap.josm.io.OsmTransferCanceledException;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.spi.preferences.Setting;
+import org.openstreetmap.josm.testutils.annotations.MockVersion;
+import org.openstreetmap.josm.testutils.annotations.fake_imagery.ColorSource;
 import org.openstreetmap.josm.testutils.mockers.EDTAssertionMocker;
 import org.openstreetmap.josm.testutils.mockers.WindowlessMapViewStateMocker;
 import org.openstreetmap.josm.testutils.mockers.WindowlessNavigatableComponentMocker;
@@ -79,8 +80,6 @@ import org.openstreetmap.josm.tools.Utils;
 import org.openstreetmap.josm.tools.bugreport.ReportedException;
 import org.openstreetmap.josm.tools.date.DateUtils;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
 /**
  * This class runs a test in an environment that resembles the one used by the JOSM main application.
  * <p>
@@ -332,10 +331,10 @@ public class JOSMTestRules implements TestRule, AfterEachCallback, BeforeEachCal
                 true,
                 true,
                 true,
-                new TileSourceRule.ColorSource(Color.WHITE, "White Tiles", 256),
-                new TileSourceRule.ColorSource(Color.BLACK, "Black Tiles", 256),
-                new TileSourceRule.ColorSource(Color.MAGENTA, "Magenta Tiles", 256),
-                new TileSourceRule.ColorSource(Color.GREEN, "Green Tiles", 256)
+                new ColorSource(Color.WHITE, "White Tiles", 256),
+                new ColorSource(Color.BLACK, "Black Tiles", 256),
+                new ColorSource(Color.MAGENTA, "Magenta Tiles", 256),
+                new ColorSource(Color.GREEN, "Green Tiles", 256)
             )
         );
     }
@@ -403,14 +402,6 @@ public class JOSMTestRules implements TestRule, AfterEachCallback, BeforeEachCal
         return this;
     }
 
-    private static class MockVersion extends Version {
-        MockVersion(final String propertiesString) {
-            super.initFromRevisionInfo(
-                new ByteArrayInputStream(propertiesString.getBytes(StandardCharsets.UTF_8))
-            );
-        }
-    }
-
     @Override
     public Statement apply(Statement base, Description description) {
         // First process any Override* annotations for per-test overrides.
diff --git a/test/unit/org/openstreetmap/josm/testutils/TileSourceRule.java b/test/unit/org/openstreetmap/josm/testutils/TileSourceRule.java
index 9156cbd539..b7fc44b687 100644
--- a/test/unit/org/openstreetmap/josm/testutils/TileSourceRule.java
+++ b/test/unit/org/openstreetmap/josm/testutils/TileSourceRule.java
@@ -5,17 +5,11 @@ import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options
 import static org.openstreetmap.josm.TestUtils.getPrivateStaticField;
 
 import java.awt.Color;
-import java.awt.Graphics2D;
-import java.awt.image.BufferedImage;
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Objects;
-
-import javax.imageio.ImageIO;
 
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
@@ -50,8 +44,13 @@ public class TileSourceRule extends WireMockRule {
 
     /**
      * Class defining a tile source for TileSourceRule to mock. Due to the way WireMock is designed, it is far more
-     * straightforward to serve a single image in all tile positions
+     * straightforward to serve a single image in all tile positions.
+     *
+     * @deprecated Please extend {@link org.openstreetmap.josm.testutils.annotations.fake_imagery.ConstSource} instead.
+     * When JUnit 4 support is removed from JOSM, this class will disappear. Until then,
+     * {@link org.openstreetmap.josm.testutils.annotations.fake_imagery.ConstSource} will extend {@link ConstSource}.
      */
+    @Deprecated
     public abstract static class ConstSource {
         /**
          * method for actually generating the payload body bytes, uncached
@@ -101,63 +100,17 @@ public class TileSourceRule extends WireMockRule {
 
     /**
      * A plain color tile source
+     * @deprecated Use {@link org.openstreetmap.josm.testutils.annotations.fake_imagery.ColorSource} instead
      */
-    public static class ColorSource extends ConstSource {
-        protected final Color color;
-        protected final String label;
-        protected final int tileSize;
-
+    @Deprecated
+    public static class ColorSource extends org.openstreetmap.josm.testutils.annotations.fake_imagery.ColorSource {
         /**
          * @param color Color for these tiles
          * @param label text label/name for this source if displayed in JOSM menus
          * @param tileSize Pixel dimension of tiles (usually 256)
          */
         public ColorSource(Color color, String label, int tileSize) {
-            this.color = color;
-            this.label = label;
-            this.tileSize = tileSize;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(this.color, this.label, this.tileSize, this.getClass());
-        }
-
-        @Override
-        public byte[] generatePayloadBytes() {
-            BufferedImage image = new BufferedImage(this.tileSize, this.tileSize, BufferedImage.TYPE_INT_RGB);
-            Graphics2D g = image.createGraphics();
-            g.setBackground(this.color);
-            g.clearRect(0, 0, image.getWidth(), image.getHeight());
-
-            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-            try {
-                ImageIO.write(image, "png", outputStream);
-            } catch (IOException e) {
-                Logging.trace(e);
-            }
-            return outputStream.toByteArray();
-        }
-
-        @Override
-        public MappingBuilder getMappingBuilder() {
-            return WireMock.get(WireMock.urlMatching(String.format("/%h/(\\d+)/(\\d+)/(\\d+)\\.png", this.hashCode())));
-        }
-
-        @Override
-        public ImageryInfo getImageryInfo(int port) {
-            return new ImageryInfo(
-                this.label,
-                String.format("tms[20]:http://localhost:%d/%h/{z}/{x}/{y}.png", port, this.hashCode()),
-                "tms",
-                (String) null,
-                (String) null
-            );
-        }
-
-        @Override
-        public String getLabel() {
-            return this.label;
+            super(color, label, tileSize);
         }
     }
 
diff --git a/test/unit/org/openstreetmap/josm/testutils/annotations/AssumeRevision.java b/test/unit/org/openstreetmap/josm/testutils/annotations/AssumeRevision.java
new file mode 100644
index 0000000000..849f06cf13
--- /dev/null
+++ b/test/unit/org/openstreetmap/josm/testutils/annotations/AssumeRevision.java
@@ -0,0 +1,69 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.testutils.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Optional;
+
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
+import org.junit.jupiter.api.extension.ExtensionContext.Store;
+import org.openstreetmap.josm.TestUtils;
+import org.openstreetmap.josm.data.Version;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+
+/**
+ * Override this test's assumed JOSM version (as reported by {@link Version}).
+ * @author Taylor Smock
+ * @see JOSMTestRules#assumeRevision(String)
+ * @since xxx
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+@ExtendWith(AssumeRevision.AssumeRevisionExtension.class)
+public @interface AssumeRevision {
+    /**
+     * Returns overridden assumed JOSM version.
+     * @return overridden assumed JOSM version
+     */
+    String value();
+
+    /**
+     * Override the JOSM revision information. Use {@link AssumeRevision} instead of directly using this extension.
+     * @author Taylor Smock
+     * @since xxx
+     */
+    class AssumeRevisionExtension implements BeforeEachCallback, AfterEachCallback {
+
+        @Override
+        public void afterEach(ExtensionContext context) throws Exception {
+            Store store = context.getStore(Namespace.create(AssumeRevisionExtension.class));
+            Version originalVersion = store.getOrDefault(Version.class, Version.class, null);
+            if (originalVersion != null) {
+                TestUtils.setPrivateStaticField(Version.class, "instance", originalVersion);
+            }
+        }
+
+        @Override
+        public void beforeEach(ExtensionContext context) throws Exception {
+            Optional<AssumeRevision> annotation = AnnotationUtils.findFirstParentAnnotation(context, AssumeRevision.class);
+            if (annotation.isPresent()) {
+                Store store = context.getStore(Namespace.create(AssumeRevisionExtension.class));
+                if (store.get(Version.class, Version.class) == null) {
+                    store.put(Version.class, Version.getInstance());
+                }
+                final Version replacementVersion = new MockVersion(annotation.get().value());
+                TestUtils.setPrivateStaticField(Version.class, "instance", replacementVersion);
+            }
+        }
+    }
+
+}
diff --git a/test/unit/org/openstreetmap/josm/testutils/annotations/BasicPreferences.java b/test/unit/org/openstreetmap/josm/testutils/annotations/BasicPreferences.java
index 1ee93ed28b..ee81391c02 100644
--- a/test/unit/org/openstreetmap/josm/testutils/annotations/BasicPreferences.java
+++ b/test/unit/org/openstreetmap/josm/testutils/annotations/BasicPreferences.java
@@ -3,9 +3,12 @@ package org.openstreetmap.josm.testutils.annotations;
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.lang.reflect.Field;
+import java.nio.file.Path;
 
 import org.junit.jupiter.api.extension.AfterAllCallback;
 import org.junit.jupiter.api.extension.AfterEachCallback;
@@ -14,11 +17,15 @@ import org.junit.jupiter.api.extension.BeforeEachCallback;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.api.extension.ExtensionContext;
 import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
+import org.junit.platform.commons.util.ClassFilter;
+import org.junit.platform.commons.util.ReflectionUtils;
 import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.preferences.AbstractProperty;
 import org.openstreetmap.josm.data.preferences.JosmBaseDirectories;
 import org.openstreetmap.josm.data.preferences.JosmUrls;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.tools.Logging;
 
 /**
  * Allow tests to use JOSM preferences (see {@link JOSMTestRules#preferences()}).
@@ -31,9 +38,15 @@ import org.openstreetmap.josm.testutils.JOSMTestRules;
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.TYPE, ElementType.METHOD})
+@Inherited
+// Force use of a new JOSM home every run (this helps avoid resetting the user's JOSM preferences, when run from an IDE)
+@JosmHome
 @ExtendWith(BasicPreferences.BasicPreferencesExtension.class)
 public @interface BasicPreferences {
 
+    /** {@code true} to clear preferences between tests. Alternatively, re-annotate specific tests with this annotation. */
+    boolean value() default false;
+
     /**
      * Initialize basic preferences. This is often more than enough for basic tests.
      * @author Taylor Smock
@@ -42,11 +55,15 @@ public @interface BasicPreferences {
         @Override
         public void afterAll(ExtensionContext context) throws Exception {
             AnnotationUtils.resetStaticClass(Config.class);
+
+            // Ensure that config tests are consistent
+            resetConfigVariables(null);
         }
 
         @Override
         public void afterEach(ExtensionContext context) throws Exception {
-            if (context.getElement().isPresent() && context.getElement().get().isAnnotationPresent(BasicPreferences.class)) {
+            if (context.getElement().isPresent() && context.getElement().get().isAnnotationPresent(BasicPreferences.class)
+            || AnnotationUtils.findFirstParentAnnotation(context, BasicPreferences.class).map(BasicPreferences::value).orElse(false)) {
                 this.afterAll(context);
             }
         }
@@ -64,13 +81,44 @@ public @interface BasicPreferences {
 
             // Store the pref for other extensions
             context.getStore(Namespace.create(BasicPreferencesExtension.class)).put("preferences", pref);
+
+            resetConfigVariables(pref);
         }
 
         @Override
         public void beforeEach(ExtensionContext context) throws Exception {
-            if (AnnotationUtils.elementIsAnnotated(context.getElement(), BasicPreferences.class) || Config.getPref() == null) {
+            if (AnnotationUtils.elementIsAnnotated(context.getElement(), BasicPreferences.class) || Config.getPref() == null
+                || AnnotationUtils.findFirstParentAnnotation(context, BasicPreferences.class).map(BasicPreferences::value).orElse(false)) {
                 this.beforeAll(context);
             }
         }
+
+        /**
+         * Reset all {@link AbstractProperty} preferences to the new preference
+         * @param pref The preference to use
+         * @throws ReflectiveOperationException if reflection fails
+         */
+        private void resetConfigVariables(Preferences pref) throws ReflectiveOperationException {
+            final Field configField = AbstractProperty.class.getDeclaredField("preferences");
+            configField.setAccessible(true);
+            for (Path classPath : ReflectionUtils.getAllClasspathRootDirectories()) {
+                for (Class<?> clazz : ReflectionUtils.findAllClassesInClasspathRoot(classPath.toUri(), ClassFilter.of(tClazz -> true))) {
+                    try {
+                        for (Field field : clazz.getDeclaredFields()) {
+                            if (ReflectionUtils.isStatic(field) && AbstractProperty.class.isAssignableFrom(field.getType())) {
+                                field.setAccessible(true);
+                                configField.set(field.get(null), pref);
+                            }
+                        }
+                    } catch (NoClassDefFoundError noClassDefFoundError) {
+                        Logging.warn("{0}: No class definition found", clazz.getName());
+                    }
+                }
+            }
+
+            // Ensure that the directories get reset as well. This is stored in the main preferences holder (Preferences.main())
+            JosmBaseDirectories.getInstance().clearMemos();
+        }
     }
 }
+
diff --git a/test/unit/org/openstreetmap/josm/testutils/annotations/BasicWiremock.java b/test/unit/org/openstreetmap/josm/testutils/annotations/BasicWiremock.java
index 2abe8efff9..cf15c5a700 100644
--- a/test/unit/org/openstreetmap/josm/testutils/annotations/BasicWiremock.java
+++ b/test/unit/org/openstreetmap/josm/testutils/annotations/BasicWiremock.java
@@ -7,6 +7,7 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
@@ -29,6 +30,7 @@ import org.junit.jupiter.api.extension.ParameterContext;
 import org.junit.jupiter.api.extension.ParameterResolutionException;
 import org.junit.jupiter.api.extension.ParameterResolver;
 import org.junit.platform.commons.support.AnnotationSupport;
+import org.junit.platform.commons.util.ReflectionUtils;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.gui.util.GuiHelper;
@@ -54,6 +56,8 @@ import com.github.tomakehurst.wiremock.verification.LoggedRequest;
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
 @ExtendWith(BasicWiremock.WireMockExtension.class)
+@ExtendWith(BasicWiremock.WireMockParameterResolver.class)
+@Inherited
 public @interface BasicWiremock {
     /**
      * Set the path for the data. Default is {@link TestUtils#getTestDataRoot()}.
@@ -78,7 +82,7 @@ public @interface BasicWiremock {
      *
      */
     class WireMockExtension
-            implements AfterAllCallback, AfterEachCallback, BeforeAllCallback, BeforeEachCallback, ParameterResolver {
+            implements AfterAllCallback, AfterEachCallback, BeforeAllCallback, BeforeEachCallback {
         /**
          * Get the default wiremock server
          * @param context The context to search
@@ -92,11 +96,11 @@ public @interface BasicWiremock {
                 final List<ResponseTransformer> transformers = new ArrayList<>(annotation.responseTransformers().length);
                 for (Class<? extends ResponseTransformer> responseTransformer : annotation.responseTransformers()) {
                     for (Pair<Class<?>[], Object[]> parameterMapping : Arrays.asList(
-                            new Pair<>(new Class<?>[] {ExtensionContext.class }, new Object[] {context }),
+                            new Pair<>(new Class<?>[] {ExtensionContext.class}, new Object[] {context}),
                             new Pair<>(new Class<?>[0], new Object[0]))) {
                         try {
-                            Constructor<? extends ResponseTransformer> constructor = responseTransformer
-                                    .getConstructor(parameterMapping.a);
+                            Constructor<? extends ResponseTransformer> constructor = responseTransformer.getConstructor(
+                                    parameterMapping.a);
                             transformers.add(constructor.newInstance(parameterMapping.b));
                             break;
                         } catch (ReflectiveOperationException e) {
@@ -104,9 +108,9 @@ public @interface BasicWiremock {
                         }
                     }
                 }
-                return new WireMockServer(
-                    options().usingFilesUnderDirectory(Utils.isStripEmpty(annotation.value()) ? TestUtils.getTestDataRoot() :
-                            annotation.value()).extensions(transformers.toArray(new ResponseTransformer[0])).dynamicPort());
+                return new WireMockServer(options().usingFilesUnderDirectory(
+                        Utils.isStripEmpty(annotation.value()) ? TestUtils.getTestDataRoot() :
+                                annotation.value()).extensions(transformers.toArray(new ResponseTransformer[0])).dynamicPort());
             }, WireMockServer.class);
         }
 
@@ -138,7 +142,8 @@ public @interface BasicWiremock {
             List<LoggedRequest> missed = getWiremock(context).findUnmatchedRequests().getRequests();
             missed.forEach(r -> Logging.error(r.getAbsoluteUrl()));
             try {
-                assertTrue(missed.isEmpty(), missed.stream().map(LoggedRequest::getUrl).collect(Collectors.joining("\n\n")));
+                assertTrue(missed.isEmpty(),
+                        missed.stream().map(LoggedRequest::getUrl).collect(Collectors.joining("\n\n")));
             } finally {
                 getWiremock(context).resetRequests();
                 getWiremock(context).resetToDefaultMappings();
@@ -153,6 +158,7 @@ public @interface BasicWiremock {
         @Override
         public void beforeAll(ExtensionContext context) throws Exception {
             getWiremock(context).start();
+            setWireMocks(context);
         }
 
         @Override
@@ -160,14 +166,28 @@ public @interface BasicWiremock {
             if (AnnotationUtils.elementIsAnnotated(context.getElement(), BasicWiremock.class) || getWiremock(context) == null) {
                 this.beforeAll(context);
             }
+            setWireMocks(context);
+        }
+
+        /**
+         * Set wiremock fields
+         * @param context The context to use
+         * @throws IllegalAccessException If the object cannot be accessed
+         */
+        private static void setWireMocks(ExtensionContext context) throws IllegalAccessException {
             if (context.getTestClass().isPresent()) {
-                List<Field> wireMockFields = AnnotationSupport.findAnnotatedFields(context.getRequiredTestClass(), BasicWiremock.class);
+                List<Field> wireMockFields = AnnotationSupport.findAnnotatedFields(context.getRequiredTestClass(),
+                        BasicWiremock.class);
                 for (Field field : wireMockFields) {
-                    if (WireMockServer.class.isAssignableFrom(field.getType())) {
+                    if (field.getType().isAssignableFrom(WireMockServer.class)) {
                         final boolean isAccessible = field.isAccessible();
                         field.setAccessible(true);
                         try {
-                            field.set(context.getTestInstance().orElse(null), getWiremock(context));
+                            if (ReflectionUtils.isStatic(field) && context.getRequiredTestClass().equals(context.getElement().orElse(null))) {
+                                field.set(null, getWiremock(context));
+                            } else if (context.getTestInstance().isPresent()) {
+                                field.set(context.getTestInstance().get(), getWiremock(context));
+                            }
                         } finally {
                             field.setAccessible(isAccessible);
                         }
@@ -176,19 +196,25 @@ public @interface BasicWiremock {
                     }
                 }
             }
+
         }
+    }
 
+    /**
+     * A specific resolver for WireMock parameters
+     */
+    class WireMockParameterResolver implements ParameterResolver {
         @Override
         public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
                 throws ParameterResolutionException {
             return parameterContext.getParameter().getAnnotation(BasicWiremock.class) != null
-                    && parameterContext.getParameter().getType() == WireMockServer.class;
+                    && parameterContext.getParameter().getType().isAssignableFrom(WireMockServer.class);
         }
 
         @Override
         public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
                 throws ParameterResolutionException {
-            return getWiremock(extensionContext);
+            return WireMockExtension.getWiremock(extensionContext);
         }
     }
 
diff --git a/test/unit/org/openstreetmap/josm/testutils/annotations/FakeImagery.java b/test/unit/org/openstreetmap/josm/testutils/annotations/FakeImagery.java
new file mode 100644
index 0000000000..db54a5af8f
--- /dev/null
+++ b/test/unit/org/openstreetmap/josm/testutils/annotations/FakeImagery.java
@@ -0,0 +1,314 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.testutils.annotations;
+
+import static org.junit.jupiter.api.Assertions.fail;
+import static org.openstreetmap.josm.TestUtils.getPrivateStaticField;
+
+import java.awt.Color;
+import java.io.IOException;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.jupiter.api.extension.ParameterResolver;
+import org.junit.platform.commons.support.AnnotationSupport;
+import org.junit.platform.commons.util.ReflectionUtils;
+import org.openstreetmap.josm.data.imagery.ImageryInfo;
+import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
+import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
+import org.openstreetmap.josm.testutils.annotations.fake_imagery.ColorSource;
+import org.openstreetmap.josm.testutils.annotations.fake_imagery.ConstSource;
+import org.openstreetmap.josm.tools.Logging;
+import org.opentest4j.AssertionFailedError;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import com.github.tomakehurst.wiremock.client.WireMock;
+
+/**
+ * An annotation for fake imagery
+ * Please note that this currently only supports single-color tile sources.
+ * @author Taylor Smock
+ * @since xxx
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
+@BasicWiremock
+@ExtendWith(FakeImagery.FakeImageryExtension.class)
+@ExtendWith(FakeImagery.FakeImageryParameterResolver.class)
+public @interface FakeImagery {
+    /**
+     * The options to use for FakeImagery
+     * @return The options
+     */
+    Options[] options() default {Options.CLEAR_LAYER_LIST, Options.CLEAR_SLIPPY_MAP_SOURCES, Options.REGISTER_IN_LAYER_LIST};
+
+    /**
+     * The color tile sources to use for FakeImagery
+     * @return The simple color tile sources
+     */
+    ColorTileSource[] colorTileSources() default {@ColorTileSource(colors = Colors.WHITE, name = "White Tiles"),
+        @ColorTileSource(colors = Colors.BLACK, name = "Black Tiles"),
+        @ColorTileSource(colors = Colors.MAGENTA, name = "Magenta Tiles"), @ColorTileSource(colors = Colors.GREEN, name = "Green Tiles")};
+
+    /**
+     * The more complex tilesources to use. The classes <i>must</i> have a constructor with no arguments
+     * @return The tile sources to instantiate
+     */
+    Class<? extends ConstSource>[] tileSources() default {};
+
+    /**
+     * Define a simple tile source (only single color supported at this time)
+     * @author Taylor Smock
+     */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.LOCAL_VARIABLE)
+    @interface ColorTileSource {
+        /**
+         * Pixel dimension of tiles (usually 256)
+         * @return The expected size for the tiles
+         */
+        int size() default 256;
+
+        /**
+         * Color for these tiles
+         * @return The Color enum (sorry, you can't make your own arbitrary colors)
+         */
+        Colors colors() default Colors.BLACK;
+
+        /**
+         * text label/name for this source if displayed in JOSM menus
+         * @return The name for the layer/menu entry
+         */
+        String name();
+    }
+
+    /**
+     * The options that can be used for FakeImagery
+     * @author Taylor Smock
+     *
+     */
+    enum Options {
+        /**
+         * whether to clear ImageryLayerInfo's layer list of any pre-existing entries
+         */
+        CLEAR_LAYER_LIST,
+        /**
+         * whether to clear SlippyMapBBoxChooser's stubborn fallback Mapnik ColorTileSource
+         */
+        CLEAR_SLIPPY_MAP_SOURCES,
+        /**
+         * whether to add sources to ImageryLayerInfo's layer list
+         */
+        REGISTER_IN_LAYER_LIST
+    }
+
+    /**
+     * An enum for colors (currently only uses static colors from {@link Color})
+     */
+    enum Colors {
+        BLACK(Color.BLACK),
+        BLUE(Color.BLUE),
+        CYAN(Color.CYAN),
+        DARK_GRAY(Color.DARK_GRAY),
+        GRAY(Color.GRAY),
+        GREEN(Color.GREEN),
+        LIGHT_GRAY(Color.LIGHT_GRAY),
+        MAGENTA(Color.MAGENTA),
+        ORANGE(Color.ORANGE),
+        PINK(Color.PINK),
+        RED(Color.RED),
+        WHITE(Color.WHITE),
+        YELLOW(Color.YELLOW);
+
+        private final Color color;
+        Colors(Color color) {
+            this.color = color;
+        }
+
+        public Color getColor() {
+            return this.color;
+        }
+    }
+
+    /**
+     * A class to specifically mock Imagery calls
+     */
+    class FakeImageryExtension extends BasicWiremock.WireMockExtension {
+        static final String SLIPPY_MAP_PROVIDERS = "slippyMapProviders";
+        static final String SLIPPY_MAP_DEFAULT_PROVIDER = "slippyMapDefaultProvider";
+        static final String ORIGINAL_IMAGERY_INFO_LIST = "originalImageryInfoList";
+
+        @Override
+        public void afterEach(ExtensionContext context) throws Exception {
+            try {
+                super.afterEach(context);
+            } finally {
+                cleanup(context);
+            }
+        }
+
+        @Override
+        public void beforeAll(ExtensionContext context) throws Exception {
+            if (context.getStore(ExtensionContext.Namespace.create(BasicPreferences.BasicPreferencesExtension.class))
+                    .get("preferences") == null) {
+                fail("FakeImageryExtension requires preferences (try @BasicPreferences)");
+            }
+            super.beforeAll(context);
+
+            // Get the wiremock server
+            final WireMockServer wireMockServer = getWiremock(context);
+
+            // set up a stub target for the early request hack
+            wireMockServer.stubFor(WireMock.get(
+                    WireMock.urlMatching("/_poke")
+            ).willReturn(WireMock.aResponse().withStatus(200).withBody("ow.")));
+            runServer(wireMockServer);
+        }
+
+        @Override
+        public void beforeEach(final ExtensionContext context) throws Exception {
+            super.beforeEach(context);
+            final FakeImagery fakeImagery = AnnotationSupport.findAnnotation(context.getElement(), FakeImagery.class)
+                    .orElseGet(() -> AnnotationSupport.findAnnotation(context.getRequiredTestClass(), FakeImagery.class)
+                    .orElseThrow((Supplier<AssertionFailedError>) () -> fail(context.getDisplayName() + " missing @FakeImagery annotation")));
+            final Set<Options> options = EnumSet.copyOf(Arrays.asList(fakeImagery.options()));
+            final ColorTileSource[] colorTileSources = fakeImagery.colorTileSources();
+            final Class<? extends ConstSource>[] additionalTileSources = fakeImagery.tileSources();
+
+            // Get the wiremock server
+            final WireMockServer wireMockServer = getWiremock(context);
+
+            final List<ConstSource> constSourceList = new ArrayList<>(colorTileSources.length + additionalTileSources.length);
+            for (ColorTileSource source : colorTileSources) {
+                final ColorSource colorSource = new ColorSource(source);
+                constSourceList.add(colorSource);
+                wireMockServer.stubFor(colorSource.getMappingBuilder().willReturn(colorSource.getResponseDefinitionBuilder()));
+            }
+
+            for (Class<? extends ConstSource> constSourceClazz : additionalTileSources) {
+                final ConstSource constSource = ReflectionUtils.newInstance(constSourceClazz);
+                constSourceList.add(constSource);
+                wireMockServer.stubFor(constSource.getMappingBuilder().willReturn(constSource.getResponseDefinitionBuilder()));
+            }
+
+            registerLayers(context, options, constSourceList, wireMockServer);
+        }
+
+        /**
+         * A hack to circumvent a WireMock bug concerning delayed server startup. sending an early request
+         * to the mock server seems to prompt it to start earlier (though this request itself is not
+         * expected to succeed). See <a href="https://github.com/tomakehurst/wiremock/issues/97">WireMock Issue #97</a>
+         */
+        private static void runServer(WireMockServer wireMockServer) {
+            try {
+                new java.net.URL(wireMockServer.url("/_poke")).getContent();
+            } catch (IOException e) {
+                Logging.trace(e);
+            }
+        }
+
+        private static void registerLayers(final ExtensionContext context, final Set<Options> options, final List<ConstSource> sourcesList,
+                final WireMockServer wireMockServer) {
+            if (options.contains(Options.REGISTER_IN_LAYER_LIST) || options.contains(Options.CLEAR_LAYER_LIST)) {
+                ExtensionContext.Store store = context.getStore(
+                        ExtensionContext.Namespace.create(FakeImageryExtension.class));
+                if (options.contains(Options.CLEAR_SLIPPY_MAP_SOURCES)) {
+                    try {
+                        final List<SlippyMapBBoxChooser.TileSourceProvider> slippyMapProviders =
+                                (List<SlippyMapBBoxChooser.TileSourceProvider>)
+                                        getPrivateStaticField(SlippyMapBBoxChooser.class, "providers");
+                        // pop this off the beginning of the list, keep for later
+                        final SlippyMapBBoxChooser.TileSourceProvider slippyMapDefaultProvider = slippyMapProviders.remove(0);
+                        store.put(SLIPPY_MAP_PROVIDERS, slippyMapProviders);
+                        store.put(SLIPPY_MAP_DEFAULT_PROVIDER, slippyMapDefaultProvider);
+                    } catch (ReflectiveOperationException e) {
+                        Logging.warn("Failed to remove default SlippyMapBBoxChooser TileSourceProvider");
+                    }
+                }
+
+                if (options.contains(Options.CLEAR_LAYER_LIST)) {
+                    final List<ImageryInfo> originalImageryInfoList = ImageryLayerInfo.instance.getLayers();
+                    store.put(ORIGINAL_IMAGERY_INFO_LIST, originalImageryInfoList);
+                    ImageryLayerInfo.instance.clear();
+                }
+                if (options.contains(Options.REGISTER_IN_LAYER_LIST)) {
+                    for (ConstSource source : sourcesList) {
+                        ImageryLayerInfo.addLayer(source.getImageryInfo(wireMockServer));
+                    }
+                }
+                store.put(ConstSource.class, sourcesList);
+            }
+        }
+
+        /**
+         * Cleanup the environment
+         * @param context The context with the original values
+         */
+        private static void cleanup(final ExtensionContext context) {
+            final ExtensionContext.Store store = context.getStore(
+                    ExtensionContext.Namespace.create(FakeImageryExtension.class));
+            final List<SlippyMapBBoxChooser.TileSourceProvider> slippyMapProviders = (List<SlippyMapBBoxChooser.TileSourceProvider>)
+                    store.remove(SLIPPY_MAP_PROVIDERS, List.class);
+            final SlippyMapBBoxChooser.TileSourceProvider slippyMapDefaultProvider = store.remove(SLIPPY_MAP_DEFAULT_PROVIDER,
+                    SlippyMapBBoxChooser.TileSourceProvider.class);
+            final List<ImageryInfo> originalImageryInfoList = (List<ImageryInfo>) store.remove(ORIGINAL_IMAGERY_INFO_LIST, List.class);
+            // clean up to original state
+            if (slippyMapDefaultProvider != null && slippyMapProviders != null) {
+                slippyMapProviders.add(0, slippyMapDefaultProvider);
+            }
+            if (originalImageryInfoList != null) {
+                ImageryLayerInfo.instance.clear();
+                ImageryLayerInfo.addLayers(originalImageryInfoList);
+            }
+        }
+    }
+
+    /**
+     * A parameter resolver for FakeImagery
+     */
+    class FakeImageryParameterResolver implements ParameterResolver {
+        @Override
+        public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
+                throws ParameterResolutionException {
+            ExtensionContext.Store store = extensionContext.getStore(
+                    ExtensionContext.Namespace.create(FakeImageryExtension.class));
+            if (store.get(ConstSource.class) != null && parameterContext.isAnnotated(FakeImagery.class)
+                    && List.class.isAssignableFrom(parameterContext.getParameter().getType())) {
+                 Optional<Method> optionalMethod = ReflectionUtils.findMethod(parameterContext.getParameter().getParameterizedType().getClass(),
+                         "getActualTypeArguments");
+                 if (!optionalMethod.isPresent() || !optionalMethod.get().getReturnType().isAssignableFrom(Type[].class)) {
+                     // We can't check the type. Therefore, we must hope that everything goes well.
+                     return true;
+                 }
+                 Type[] types = (Type[]) ReflectionUtils.invokeMethod(optionalMethod.get(),
+                         parameterContext.getParameter().getParameterizedType());
+                 return types.length == 1 && ConstSource.class.isAssignableFrom((Class<?>) types[0]);
+            }
+            return false;
+        }
+
+        @Override
+        public List<ConstSource> resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext)
+                throws ParameterResolutionException {
+            ExtensionContext.Store store = extensionContext.getStore(
+                    ExtensionContext.Namespace.create(FakeImageryExtension.class));
+            return (List<ConstSource>) store.get(ConstSource.class, List.class);
+        }
+    }
+}
diff --git a/test/unit/org/openstreetmap/josm/testutils/annotations/FullPreferences.java b/test/unit/org/openstreetmap/josm/testutils/annotations/FullPreferences.java
index 92fa0844e5..42d07918df 100644
--- a/test/unit/org/openstreetmap/josm/testutils/annotations/FullPreferences.java
+++ b/test/unit/org/openstreetmap/josm/testutils/annotations/FullPreferences.java
@@ -29,7 +29,6 @@ import org.openstreetmap.josm.testutils.annotations.BasicPreferences.BasicPrefer
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.TYPE, ElementType.METHOD})
-@JosmHome
 @BasicPreferences
 @ExtendWith(FullPreferences.UsePreferencesExtension.class)
 public @interface FullPreferences {
diff --git a/test/unit/org/openstreetmap/josm/testutils/annotations/IntegrationTest.java b/test/unit/org/openstreetmap/josm/testutils/annotations/IntegrationTest.java
new file mode 100644
index 0000000000..e1698055b6
--- /dev/null
+++ b/test/unit/org/openstreetmap/josm/testutils/annotations/IntegrationTest.java
@@ -0,0 +1,24 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.testutils.annotations;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import org.junit.jupiter.api.Tag;
+
+/**
+ * Integration Tests annotation (JUnit5 can filter tests with/without this annotation)
+ * @author Taylor Smock
+ * @since xxx
+ */
+@Documented
+@Retention(RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Tag("integrationTest")
+public @interface IntegrationTest {
+
+}
diff --git a/test/unit/org/openstreetmap/josm/testutils/annotations/JosmHome.java b/test/unit/org/openstreetmap/josm/testutils/annotations/JosmHome.java
index c51d0e00f4..61075fbe2f 100644
--- a/test/unit/org/openstreetmap/josm/testutils/annotations/JosmHome.java
+++ b/test/unit/org/openstreetmap/josm/testutils/annotations/JosmHome.java
@@ -16,7 +16,9 @@ import java.nio.file.attribute.BasicFileAttributes;
 import java.util.UUID;
 
 import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.AfterEachCallback;
 import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.api.extension.ExtensionContext;
 import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
@@ -25,7 +27,7 @@ import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 /**
  * Use the JOSM home directory. See {@link JOSMTestRules}.
- * Typically only used by {@link FullPreferences}.
+ * Called by {@link BasicPreferences}.
  *
  * @author Taylor Smock
  * @since 18037
@@ -39,7 +41,7 @@ public @interface JosmHome {
      * Create a JOSM home directory. Prefer using {@link JosmHome}.
      * @author Taylor Smock
      */
-    class JosmHomeExtension implements BeforeAllCallback, AfterAllCallback {
+    class JosmHomeExtension implements BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback {
         @Override
         public void afterAll(ExtensionContext context) throws Exception {
             Path tempDir = context.getStore(Namespace.create(JosmHome.class)).get("home", Path.class);
@@ -66,5 +68,36 @@ public @interface JosmHome {
             System.setProperty("josm.home", home.getAbsolutePath());
             JosmBaseDirectories.getInstance().clearMemos();
         }
+
+        @Override
+        public void afterEach(ExtensionContext context) throws Exception {
+            if (shouldRun(context)) {
+                this.afterAll(context);
+                // Restore the "original" home
+                ExtensionContext.Store store = context.getStore(Namespace.create(JosmHome.class));
+                Path oldHome = store.get("old_home", Path.class);
+                System.setProperty("josm.home", oldHome.toFile().getAbsolutePath());
+                JosmBaseDirectories.getInstance().clearMemos();
+            }
+        }
+
+        @Override
+        public void beforeEach(ExtensionContext context) throws Exception {
+            if (shouldRun(context)) {
+                // Store the "original" home
+                ExtensionContext.Store store = context.getStore(Namespace.create(JosmHome.class));
+                store.put("old_home", store.get("home", Path.class));
+                this.beforeAll(context);
+            }
+        }
+
+        /**
+         * Check if this should run before/after each test
+         * @param context The context to use
+         * @return {@code true} if we should change home directories before/after each test
+         */
+        private boolean shouldRun(ExtensionContext context) {
+            return AnnotationUtils.findFirstParentAnnotation(context, BasicPreferences.class).map(BasicPreferences::value).orElse(false);
+        }
     }
 }
diff --git a/test/unit/org/openstreetmap/josm/testutils/annotations/Main.java b/test/unit/org/openstreetmap/josm/testutils/annotations/Main.java
new file mode 100644
index 0000000000..1d430563b0
--- /dev/null
+++ b/test/unit/org/openstreetmap/josm/testutils/annotations/Main.java
@@ -0,0 +1,89 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.testutils.annotations;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.util.Optional;
+
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.platform.commons.support.AnnotationSupport;
+import org.openstreetmap.josm.JOSMFixture;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.mockers.WindowlessMapViewStateMocker;
+import org.openstreetmap.josm.testutils.mockers.WindowlessNavigatableComponentMocker;
+
+/**
+ * Use the {@link MainApplication#main}, {@code Main.contentPanePrivate}, {@code Main.mainPanel}, global variables in this test.
+ * @author Taylor Smock
+ * @see JOSMTestRules#main()
+ * @since xxx
+ */
+@Documented
+@Retention(RUNTIME)
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@BasicPreferences
+@HTTP // Prevent MOTD from throwing
+@ExtendWith(Main.MainExtension.class)
+public @interface Main {
+    /**
+     * Get the class to use as the mocker for the map view
+     * @return The mocker class for the map view
+     */
+    Class<?> mapViewStateMocker() default WindowlessMapViewStateMocker.class;
+
+    /**
+     * Get the class to use for the navigable component
+     * @return The class to use for the navigable component.
+     */
+    Class<?> navigableComponentMocker() default WindowlessNavigatableComponentMocker.class;
+
+    /**
+     * Initialize the MainApplication
+     * @author Taylor Smock
+     */
+    class MainExtension implements BeforeEachCallback, AfterEachCallback {
+        @Override
+        public void afterEach(ExtensionContext context) throws Exception {
+            synchronized (MainExtension.class) {
+                MainApplication.getLayerManager().resetState();
+                AnnotationUtils.resetStaticClass(MainApplication.class);
+            }
+        }
+
+        @Override
+        public void beforeEach(ExtensionContext context) throws Exception {
+            Optional<Main> annotation = AnnotationSupport.findAnnotation(context.getElement(), Main.class);
+            Class<?> mapViewStateMocker = null;
+            Class<?> navigableComponentMocker = null;
+            if (annotation.isPresent()) {
+                mapViewStateMocker = annotation.get().mapViewStateMocker();
+                navigableComponentMocker = annotation.get().navigableComponentMocker();
+            }
+
+            // apply mockers to MapViewState and NavigableComponent whether we're headless or not
+            // as we generally don't create the josm main window even in non-headless mode.
+            if (mapViewStateMocker != null) {
+                mapViewStateMocker.getConstructor().newInstance();
+            }
+            if (navigableComponentMocker != null) {
+                navigableComponentMocker.getConstructor().newInstance();
+            }
+
+            synchronized (MainExtension.class) {
+                new MainApplication();
+                JOSMFixture.initContentPane();
+                JOSMFixture.initMainPanel(true);
+                JOSMFixture.initToolbar();
+                JOSMFixture.initMainMenu();
+            }
+        }
+    }
+}
diff --git a/test/unit/org/openstreetmap/josm/testutils/annotations/MockVersion.java b/test/unit/org/openstreetmap/josm/testutils/annotations/MockVersion.java
new file mode 100644
index 0000000000..12ee7530c8
--- /dev/null
+++ b/test/unit/org/openstreetmap/josm/testutils/annotations/MockVersion.java
@@ -0,0 +1,18 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.testutils.annotations;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.openstreetmap.josm.data.Version;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+/**
+ * This is only publicly available for {@link JOSMTestRules#assumeRevision(String)}.
+ * This may (and probably will) become a private class in the future.
+ */
+public class MockVersion extends Version {
+    public MockVersion(final String propertiesString) {
+        super.initFromRevisionInfo(new ByteArrayInputStream(propertiesString.getBytes(StandardCharsets.UTF_8)));
+    }
+}
diff --git a/test/unit/org/openstreetmap/josm/testutils/annotations/OsmApiType.java b/test/unit/org/openstreetmap/josm/testutils/annotations/OsmApiType.java
new file mode 100644
index 0000000000..11a5bd8b23
--- /dev/null
+++ b/test/unit/org/openstreetmap/josm/testutils/annotations/OsmApiType.java
@@ -0,0 +1,98 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.testutils.annotations;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.util.Optional;
+
+import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.openstreetmap.josm.io.OsmApi;
+import org.openstreetmap.josm.spi.preferences.Config;
+import org.openstreetmap.josm.testutils.FakeOsmApi;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+/**
+ * Specify the OSM API to use for the test. {@link APIType#NONE} has no effect.
+ *
+ * @author Taylor Smock
+ * @see JOSMTestRules#devAPI()
+ * @see JOSMTestRules#fakeAPI()
+ * @since xxx
+ */
+@Documented
+@Retention(RUNTIME)
+@Target({ TYPE, METHOD })
+@FullPreferences
+@HTTP
+@ExtendWith(OsmApiType.OsmApiTypeExtension.class)
+public @interface OsmApiType {
+    /**
+     * The API type to use
+     * @return The API type to use (default NONE)
+     */
+    APIType value() default APIType.NONE;
+
+    /**
+     * API types to initialize
+     * @author Taylor Smock
+     *
+     */
+    enum APIType {
+        NONE, FAKE, DEV
+    }
+
+    /**
+     * Initialize the OSM api
+     * @author Taylor Smock
+     *
+     */
+    class OsmApiTypeExtension implements AfterAllCallback, AfterEachCallback, BeforeAllCallback, BeforeEachCallback {
+        @Override
+        public void afterAll(ExtensionContext context) throws Exception {
+            afterEach(context);
+        }
+
+        @Override
+        public void afterEach(ExtensionContext context) throws Exception {
+            // Reset to none
+            Config.getPref().put("osm-server.url", null);
+            AnnotationUtils.resetStaticClass(OsmApi.class);
+        }
+
+        @Override
+        public void beforeAll(ExtensionContext context) throws Exception {
+            beforeEach(context);
+        }
+
+        @Override
+        public void beforeEach(ExtensionContext context) throws Exception {
+            Optional<OsmApiType> annotation = AnnotationUtils.findFirstParentAnnotation(context, OsmApiType.class);
+            APIType useAPI = APIType.NONE;
+            if (annotation.isPresent()) {
+                useAPI = annotation.get().value();
+            }
+            // Set API
+            if (useAPI == APIType.DEV) {
+                Config.getPref().put("osm-server.url", "https://api06.dev.openstreetmap.org/api");
+            } else if (useAPI == APIType.FAKE) {
+                FakeOsmApi api = FakeOsmApi.getInstance();
+                Config.getPref().put("osm-server.url", api.getServerUrl());
+            }
+
+            // Initialize API
+            if (useAPI != APIType.NONE) {
+                OsmApi.getOsmApi().initialize(null);
+            }
+        }
+    }
+}
diff --git a/test/unit/org/openstreetmap/josm/testutils/annotations/Projection.java b/test/unit/org/openstreetmap/josm/testutils/annotations/Projection.java
new file mode 100644
index 0000000000..0d0ce136ae
--- /dev/null
+++ b/test/unit/org/openstreetmap/josm/testutils/annotations/Projection.java
@@ -0,0 +1,67 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.testutils.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Optional;
+
+import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.platform.commons.support.AnnotationSupport;
+import org.openstreetmap.josm.data.projection.ProjectionRegistry;
+import org.openstreetmap.josm.data.projection.Projections;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+/**
+ * Use projections in tests (Mercator).
+ * @author Taylor Smock
+ * @see JOSMTestRules#projection()
+ *
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+@ExtendWith(Projection.ProjectionExtension.class)
+public @interface Projection {
+    /**
+     * The value to use for the projection. Defaults to EPSG:3857 (Mercator).
+     * @return The value to use to get the projection from {@link Projections#getProjectionByCode}.
+     */
+    String projectionCode() default "EPSG:3857";
+
+    /**
+     * Use projections in tests. Use {@link Projection} preferentially.
+     * @author Taylor Smock
+     *
+     */
+    class ProjectionExtension implements BeforeEachCallback, BeforeAllCallback, AfterAllCallback {
+        @Override
+        public void afterAll(ExtensionContext context) throws Exception {
+            ProjectionRegistry.clearProjectionChangeListeners();
+            AnnotationUtils.resetStaticClass(ProjectionRegistry.class);
+        }
+
+        @Override
+        public void beforeAll(ExtensionContext context) throws Exception {
+            // Needed in order to run prior to Territories
+            beforeEach(context);
+        }
+
+        @Override
+        public void beforeEach(ExtensionContext context) throws Exception {
+            Optional<Projection> annotation = AnnotationSupport.findAnnotation(context.getElement(), Projection.class);
+            if (annotation.isPresent()) {
+                ProjectionRegistry.setProjection(Projections.getProjectionByCode(annotation.get().projectionCode()));
+            } else {
+                ProjectionRegistry.setProjection(Projections.getProjectionByCode("EPSG:3857")); // Mercator
+            }
+        }
+
+    }
+}
diff --git a/test/unit/org/openstreetmap/josm/testutils/annotations/Territories.java b/test/unit/org/openstreetmap/josm/testutils/annotations/Territories.java
new file mode 100644
index 0000000000..5a552bfa04
--- /dev/null
+++ b/test/unit/org/openstreetmap/josm/testutils/annotations/Territories.java
@@ -0,0 +1,83 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.testutils.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Optional;
+
+import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.platform.commons.support.AnnotationSupport;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+/**
+ * Use boundaries dataset in this test.
+ * @see JOSMTestRules#territories()
+ * @author Taylor Smock
+ * @since xxx
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@BasicPreferences // Needed for nodes
+@Projection // Needed for getEastNorth
+@ExtendWith(Territories.TerritoriesExtension.class)
+public @interface Territories {
+    /**
+     * Initialization states. Please note that the highest initialization state holds.
+     * @author Taylor Smock
+     */
+    enum Initialize {
+        /** Don't initialize */
+        NONE,
+        /** Initialize only internal data */
+        INTERNAL,
+        /** Initialize internal and external data. Requires {@link HTTP}. */
+        ALL
+    }
+
+    /**
+     * The way to initialize Territories
+     * @return The value to use
+     */
+    Initialize value() default Initialize.INTERNAL;
+
+    /**
+     * Initialize boundaries prior to use
+     * @author Taylor Smock
+     *
+     */
+    class TerritoriesExtension implements BeforeAllCallback, AfterAllCallback {
+        /** This state is only used to avoid re-initializing the Territories class */
+        private static Initialize state = Initialize.NONE;
+        @Override
+        public void afterAll(ExtensionContext context) throws Exception {
+            synchronized (TerritoriesExtension.class) {
+                // TODO org.openstreetmap.josm.tools.Territories.uninitialize();
+            }
+        }
+
+        @Override
+        public void beforeAll(ExtensionContext context) throws Exception {
+            Optional<Territories> annotation = AnnotationSupport.findAnnotation(context.getElement(), Territories.class);
+            if (annotation.isPresent()) {
+                Initialize current = annotation.get().value();
+                // Avoid potential race conditions if tests are parallelized
+                synchronized (TerritoriesExtension.class) {
+                    if (current == Initialize.INTERNAL && state != Initialize.ALL && state != Initialize.INTERNAL) {
+                        org.openstreetmap.josm.tools.Territories.initializeInternalData();
+                        state = Initialize.INTERNAL;
+                    } else if (current == Initialize.ALL && state != Initialize.ALL) {
+                        org.openstreetmap.josm.tools.Territories.initialize();
+                        state = Initialize.ALL;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/test/unit/org/openstreetmap/josm/testutils/annotations/fake_imagery/ColorSource.java b/test/unit/org/openstreetmap/josm/testutils/annotations/fake_imagery/ColorSource.java
new file mode 100644
index 0000000000..b06d502f4d
--- /dev/null
+++ b/test/unit/org/openstreetmap/josm/testutils/annotations/fake_imagery/ColorSource.java
@@ -0,0 +1,84 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.testutils.annotations.fake_imagery;
+
+import javax.imageio.ImageIO;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Objects;
+
+import org.openstreetmap.josm.data.imagery.ImageryInfo;
+import org.openstreetmap.josm.testutils.annotations.FakeImagery;
+import org.openstreetmap.josm.tools.Logging;
+
+import com.github.tomakehurst.wiremock.client.MappingBuilder;
+import com.github.tomakehurst.wiremock.client.WireMock;
+
+/**
+ * A plain color tile source
+ * @since xxx
+ */
+public class ColorSource extends ConstSource {
+    protected final Color color;
+    protected final String label;
+    protected final int tileSize;
+
+    /**
+     * Create a new ColorSource
+     * @param colorTileSource The tile source to use
+     */
+    public ColorSource(final FakeImagery.ColorTileSource colorTileSource) {
+        this(colorTileSource.colors().getColor(), colorTileSource.name(), colorTileSource.size());
+    }
+
+    /**
+     * @param color Color for these tiles
+     * @param label text label/name for this source if displayed in JOSM menus
+     * @param tileSize Pixel dimension of tiles (usually 256)
+     */
+    public ColorSource(Color color, String label, int tileSize) {
+        this.color = color;
+        this.label = label;
+        this.tileSize = tileSize;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(this.color, this.label, this.tileSize, this.getClass());
+    }
+
+    @Override
+    public byte[] generatePayloadBytes() {
+        BufferedImage image = new BufferedImage(this.tileSize, this.tileSize, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g = image.createGraphics();
+        g.setBackground(this.color);
+        g.clearRect(0, 0, image.getWidth(), image.getHeight());
+
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        try {
+            ImageIO.write(image, "png", outputStream);
+        } catch (IOException e) {
+            Logging.trace(e);
+        }
+        return outputStream.toByteArray();
+    }
+
+    @Override
+    public MappingBuilder getMappingBuilder() {
+        return WireMock.get(WireMock.urlMatching(String.format("/%h/(\\d+)/(\\d+)/(\\d+)\\.png", this.hashCode())));
+    }
+
+    @Override
+    public ImageryInfo getImageryInfo(int port) {
+        return new ImageryInfo(this.label,
+                String.format("tms[20]:http://localhost:%d/%h/{z}/{x}/{y}.png", port, this.hashCode()), "tms",
+                (String) null, (String) null);
+    }
+
+    @Override
+    public String getLabel() {
+        return this.label;
+    }
+}
diff --git a/test/unit/org/openstreetmap/josm/testutils/annotations/fake_imagery/ConstSource.java b/test/unit/org/openstreetmap/josm/testutils/annotations/fake_imagery/ConstSource.java
new file mode 100644
index 0000000000..cd3fa37e0c
--- /dev/null
+++ b/test/unit/org/openstreetmap/josm/testutils/annotations/fake_imagery/ConstSource.java
@@ -0,0 +1,32 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.testutils.annotations.fake_imagery;
+
+import org.openstreetmap.josm.data.imagery.ImageryInfo;
+import org.openstreetmap.josm.testutils.TileSourceRule;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+
+/**
+ * Class defining a tile source for TileSourceRule to mock. Due to the way WireMock is designed, it is far more
+ * straightforward to serve a single image in all tile positions
+ *
+ * Please note that this extends {@link TileSourceRule.ConstSource} for compatibility reasons.
+ * {@link TileSourceRule} may be removed in the future.
+ * @since xxx
+ */
+public abstract class ConstSource extends TileSourceRule.ConstSource {
+    // This class should have the same body as {@link TileSourceRule.ConstSource}
+    // For now, this class solely exists for transitioning off of JUnit 4 (the assumption is that JOSM will
+    // eventually remove all JUnit 4 dependent classes, at which point the parent class will be deleted, and its
+    // body moved here).
+
+    /**
+     * Get the imagery info object for the specified wiremock server (use this instead of the port-based method)
+     * @param wireMockServer The wiremock server to use
+     * @return The URL for the object
+     */
+    public ImageryInfo getImageryInfo(final WireMockServer wireMockServer) {
+        // When main body is moved here, mark getImageryInfo(int port) as deprecated
+        return this.getImageryInfo(wireMockServer.port());
+    }
+}
diff --git a/test/unit/org/openstreetmap/josm/tools/ExceptionUtilTest.java b/test/unit/org/openstreetmap/josm/tools/ExceptionUtilTest.java
index 77bef7ea66..a7d9c5e351 100644
--- a/test/unit/org/openstreetmap/josm/tools/ExceptionUtilTest.java
+++ b/test/unit/org/openstreetmap/josm/tools/ExceptionUtilTest.java
@@ -22,6 +22,7 @@ import org.openstreetmap.josm.io.OsmApiException;
 import org.openstreetmap.josm.io.OsmApiInitializationException;
 import org.openstreetmap.josm.io.auth.CredentialsManager;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.date.DateUtils;
 import org.openstreetmap.josm.tools.date.DateUtilsTest;
 
@@ -30,6 +31,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests of {@link ExceptionUtil} class.
  */
+@BasicPreferences
 class ExceptionUtilTest {
 
     /**
@@ -37,7 +39,7 @@ class ExceptionUtilTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().fakeAPI();
+    public JOSMTestRules test = new JOSMTestRules().fakeAPI();
 
     private static String baseUrl;
     private static String serverUrl;
diff --git a/test/unit/org/openstreetmap/josm/tools/GeometryTest.java b/test/unit/org/openstreetmap/josm/tools/GeometryTest.java
index b58c6d24e2..67ef2a94cb 100644
--- a/test/unit/org/openstreetmap/josm/tools/GeometryTest.java
+++ b/test/unit/org/openstreetmap/josm/tools/GeometryTest.java
@@ -36,19 +36,21 @@ import org.openstreetmap.josm.data.projection.ProjectionRegistry;
 import org.openstreetmap.josm.data.projection.Projections;
 import org.openstreetmap.josm.io.OsmReader;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 
 /**
  * Unit tests of {@link Geometry} class.
  */
+@BasicPreferences
 class GeometryTest {
     /**
      * Primitives need preferences and projection.
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().projection();
+    public JOSMTestRules test = new JOSMTestRules().projection();
 
     /**
      * Test of {@link Geometry#getLineLineIntersection} method.
diff --git a/test/unit/org/openstreetmap/josm/tools/OsmPrimitiveImageProviderTest.java b/test/unit/org/openstreetmap/josm/tools/OsmPrimitiveImageProviderTest.java
index 87830b2d75..eaaae8f40f 100644
--- a/test/unit/org/openstreetmap/josm/tools/OsmPrimitiveImageProviderTest.java
+++ b/test/unit/org/openstreetmap/josm/tools/OsmPrimitiveImageProviderTest.java
@@ -19,6 +19,7 @@ import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresets;
 import org.openstreetmap.josm.gui.tagging.presets.TaggingPresetsTest;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 import org.openstreetmap.josm.tools.OsmPrimitiveImageProvider.Options;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -26,6 +27,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 /**
  * Unit tests of {@link OsmPrimitiveImageProvider}
  */
+@BasicPreferences
 class OsmPrimitiveImageProviderTest {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/tools/PlatformHookTestIT.java b/test/unit/org/openstreetmap/josm/tools/PlatformHookTestIT.java
index 7e4b5169de..8181596e02 100644
--- a/test/unit/org/openstreetmap/josm/tools/PlatformHookTestIT.java
+++ b/test/unit/org/openstreetmap/josm/tools/PlatformHookTestIT.java
@@ -14,10 +14,12 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.IntegrationTest;
 
 /**
  * Integration tests of {@link PlatformHook} class.
  */
+@IntegrationTest
 class PlatformHookTestIT {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/tools/PlatformHookWindowsTest.java b/test/unit/org/openstreetmap/josm/tools/PlatformHookWindowsTest.java
index a77f57e97d..361f5e7e23 100644
--- a/test/unit/org/openstreetmap/josm/tools/PlatformHookWindowsTest.java
+++ b/test/unit/org/openstreetmap/josm/tools/PlatformHookWindowsTest.java
@@ -20,6 +20,7 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.TestUtils;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import mockit.Expectations;
@@ -28,6 +29,7 @@ import mockit.Mocked;
 /**
  * Unit tests of {@link PlatformHookWindows} class.
  */
+@BasicPreferences
 class PlatformHookWindowsTest {
 
     /**
@@ -35,7 +37,7 @@ class PlatformHookWindowsTest {
      */
     @RegisterExtension
     @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences().https();
+    public JOSMTestRules test = new JOSMTestRules().https();
 
     static PlatformHookWindows hook;
 
diff --git a/test/unit/org/openstreetmap/josm/tools/TerritoriesTestIT.java b/test/unit/org/openstreetmap/josm/tools/TerritoriesTestIT.java
index f0c25d8c7f..b88d82569a 100644
--- a/test/unit/org/openstreetmap/josm/tools/TerritoriesTestIT.java
+++ b/test/unit/org/openstreetmap/josm/tools/TerritoriesTestIT.java
@@ -11,10 +11,12 @@ import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.openstreetmap.josm.testutils.annotations.IntegrationTest;
 
 /**
  * Integration tests of {@link Territories} class.
  */
+@IntegrationTest
 class TerritoriesTestIT {
 
     /**
diff --git a/test/unit/org/openstreetmap/josm/tools/date/DateUtilsTest.java b/test/unit/org/openstreetmap/josm/tools/date/DateUtilsTest.java
index bc3d94c3d8..c2a5ade9fb 100644
--- a/test/unit/org/openstreetmap/josm/tools/date/DateUtilsTest.java
+++ b/test/unit/org/openstreetmap/josm/tools/date/DateUtilsTest.java
@@ -20,25 +20,21 @@ import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
+import org.openstreetmap.josm.testutils.annotations.I18n;
 import org.openstreetmap.josm.tools.UncheckedParseException;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import net.trajano.commons.testing.UtilityClassTestUtil;
 
 /**
  * Unit tests of {@link DateUtils} class.
  */
+@I18n
+@BasicPreferences
 public class DateUtilsTest {
-
-    /**
-     * Set the timezone and timeout.
-     * <p>
-     * Timeouts need to be disabled because we change the time zone.
-     */
+    // Solely needed for setting clock to UTC. To be replaced with @TimeZoneAnnotation
     @RegisterExtension
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().i18n().preferences();
-
+    JOSMTestRules josmTestRules = new JOSMTestRules();
     /**
      * Tests that {@code DateUtils} satisfies utility class criteria.
      * @throws ReflectiveOperationException if an error occurs
diff --git a/test/unit/org/openstreetmap/josm/tools/date/IntervalTest.java b/test/unit/org/openstreetmap/josm/tools/date/IntervalTest.java
index fe59d460cf..4b8bbe18f1 100644
--- a/test/unit/org/openstreetmap/josm/tools/date/IntervalTest.java
+++ b/test/unit/org/openstreetmap/josm/tools/date/IntervalTest.java
@@ -1,26 +1,17 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.tools.date;
 
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
-import org.openstreetmap.josm.testutils.JOSMTestRules;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import java.time.Instant;
 import java.util.Locale;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
 
+@BasicPreferences
 class IntervalTest {
-
-    /**
-     * Setup test.
-     */
-    @RegisterExtension
-    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
-    public JOSMTestRules test = new JOSMTestRules().preferences();
-
     /**
      * Setup test.
      */
