diff --git a/.travis.yml b/.travis.yml
index 716562cb3..ec67289fd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,22 +13,16 @@ env:
 matrix:
   fast_finish: true
   include:
-    - php: 7.2
-      env: DB=PGSQL PHPUNIT_TEST=1 PHPCS_TEST=1
     - php: 7.3
-      env: DB=MYSQL PHPUNIT_TEST=1
-    - php: 7.3
-      env: DB=MYSQL PDO=1 PHPUNIT_COVERAGE_TEST=1
+      env: DB=MYSQL PDO=1 PHPUNIT_TEST=1  PHPCS_TEST=1
     - php: 7.4
-      env: DB=MYSQL PHPUNIT_TEST=1
+      env: DB=PGSQL PHPUNIT_TEST=1 PHPUNIT_COVERAGE_TEST=1
     - php: 7.3
       env: DB=MYSQL BEHAT_TEST=1
-    - php: 7.3
+    - php: 7.4
       env: DB=MYSQL ASSETADMIN_TEST=1
-  # TODO https://github.com/silverstripe/silverstripe-asset-admin/issues/1163
-  allow_failures:
-    - php: 7.3
-      env: DB=MYSQL BEHAT_TEST=1
+    - php: 8.0
+      env: DB=MYSQL PHPUNIT_TEST=1
 
 before_script:
   # separately create artifacts directory for asset-admin behat test
diff --git a/composer.json b/composer.json
index e8a41f3d5..2bbd072b0 100755
--- a/composer.json
+++ b/composer.json
@@ -4,14 +4,14 @@
     "type": "silverstripe-vendormodule",
     "license": "BSD-3-Clause",
     "require": {
-        "silverstripe/framework": "^4",
+        "php": "^7.3 || ^8.0",
+        "silverstripe/framework": "^4.10",
         "silverstripe/vendor-plugin": "^1.0",
         "webonyx/graphql-php": "^14.0",
         "silverstripe/event-dispatcher": "^0.1.2"
     },
     "require-dev": {
-        "sminnee/phpunit": "^5.7",
-        "sminnee/phpunit-mock-objects": "^3.4.5",
+        "phpunit/phpunit": "^9.5",
         "squizlabs/php_codesniffer": "^3.0",
 		"silverstripe/versioned": "^1.0@dev"
     },
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 5c53cbdd9..0281bef32 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,8 +1,10 @@
 <phpunit bootstrap="vendor/silverstripe/framework/tests/bootstrap.php" colors="true">
 
-    <testsuite name="Default">
-        <directory>tests</directory>
-    </testsuite>
+    <testsuites>
+        <testsuite name="Default">
+            <directory>tests</directory>
+        </testsuite>
+    </testsuites>
 
     <filter>
         <whitelist addUncoveredFilesFromWhitelist="true">
diff --git a/tests/Auth/HandlerTest.php b/tests/Auth/HandlerTest.php
index a5ef24fe5..c00c2b326 100644
--- a/tests/Auth/HandlerTest.php
+++ b/tests/Auth/HandlerTest.php
@@ -22,7 +22,7 @@ class HandlerTest extends SapphireTest
     /**
      * {@inheritDoc}
      */
-    protected function setUp() : void
+    protected function setUp(): void
     {
         parent::setUp();
         Handler::config()->remove('authenticators');
diff --git a/tests/Middleware/CSRFMiddlewareTest.php b/tests/Middleware/CSRFMiddlewareTest.php
index 8e6acbdf5..4f758561a 100644
--- a/tests/Middleware/CSRFMiddlewareTest.php
+++ b/tests/Middleware/CSRFMiddlewareTest.php
@@ -23,7 +23,7 @@ public function testItDoesntDoAnythingIfNotAMutation()
     public function testItThrowsIfNoTokenIsProvided()
     {
         $this->expectException(Exception::class);
-        $this->expectExceptionMessageRegExp('/must provide a CSRF token/');
+        $this->expectExceptionMessageMatches('/must provide a CSRF token/');
         $result = $this->simulateMiddlewareProcess(
             new CSRFMiddleware(),
             ' mutation someMutation { tester }'
@@ -69,7 +69,7 @@ public function testItThrowsIfNoTokenIsProvided()
     public function testItThrowsIfTokenIsInvalid()
     {
         $this->expectException(Exception::class);
-        $this->expectExceptionMessageRegExp('/Invalid CSRF token/');
+        $this->expectExceptionMessageMatches('/Invalid CSRF token/');
         $result = $this->simulateMiddlewareProcess(
             new CSRFMiddleware(),
             ' mutation someMutation { tester }',
diff --git a/tests/Middleware/MiddlewareProcessTestBase.php b/tests/Middleware/MiddlewareProcessTestBase.php
index 929e91e5a..d7ee42ef3 100644
--- a/tests/Middleware/MiddlewareProcessTestBase.php
+++ b/tests/Middleware/MiddlewareProcessTestBase.php
@@ -16,7 +16,7 @@ abstract class MiddlewareProcessTestBase extends SapphireTest
      */
     protected $defaultCallback;
 
-    protected function setUp()
+    protected function setUp(): void
     {
         parent::setUp();
         $this->defaultCallback = function () {
diff --git a/tests/Schema/DataObject/FieldAccessorTest.php b/tests/Schema/DataObject/FieldAccessorTest.php
index c024bf8cd..7bc680436 100644
--- a/tests/Schema/DataObject/FieldAccessorTest.php
+++ b/tests/Schema/DataObject/FieldAccessorTest.php
@@ -32,7 +32,7 @@ class FieldAccessorTest extends SapphireTest
         Member::class,
     ];
 
-    protected function setUp()
+    protected function setUp(): void
     {
         parent::setUp();
         $this->obj = new FakeProduct();
diff --git a/tests/Schema/IntegrationTest.php b/tests/Schema/IntegrationTest.php
index 1fe360f71..3424ce37e 100644
--- a/tests/Schema/IntegrationTest.php
+++ b/tests/Schema/IntegrationTest.php
@@ -44,13 +44,13 @@ class IntegrationTest extends SapphireTest
         Member::class,
     ];
 
-    protected function setUp()
+    protected function setUp(): void
     {
         parent::setUp();
         TestStoreCreator::$dir = __DIR__;
     }
 
-    protected function tearDown()
+    protected function tearDown(): void
     {
         parent::tearDown();
         $this->clean();
diff --git a/tests/Schema/SchemaTest.php b/tests/Schema/SchemaTest.php
index ac65afdae..d0d1f467c 100644
--- a/tests/Schema/SchemaTest.php
+++ b/tests/Schema/SchemaTest.php
@@ -23,7 +23,7 @@
 
 class SchemaTest extends SapphireTest
 {
-    protected function setUp()
+    protected function setUp(): void
     {
         parent::setUp();
         // Kill the global schema