diff --git a/tests/phpunit/CRM/Stripe/BaseTest.php b/tests/phpunit/CRM/Stripe/BaseTest.php
index f44b1874332a704a49b5f0d1212f5ad952693885..b9af70ad8f120fbcec909d193b5a1b0aef392d8e 100644
--- a/tests/phpunit/CRM/Stripe/BaseTest.php
+++ b/tests/phpunit/CRM/Stripe/BaseTest.php
@@ -47,24 +47,38 @@ class CRM_Stripe_BaseTest extends \PHPUnit\Framework\TestCase implements Headles
   protected $total = '400.00';
 
   public function setUpHeadless() {
-    return \Civi\Test::headless()
-      ->install('mjwshared')
-      ->installMe(__DIR__)
-      ->apply();
   }
 
-  public function setUp() {
+  public function setUp(): void {
     parent::setUp();
+    // we only need to do the shared library once
+    if (!is_dir(__DIR__ . '/../../../../../mjwshared')) {
+      civicrm_api3('Extension', 'download', ['key' => 'mjwshared']);
+    }
+    else {
+      civicrm_api3('Extension', 'install', ['keys' => 'mjwshared']);
+    }
+    civicrm_api3('Extension', 'install', ['keys' => 'com.drastikbydesign.stripe']);
     require_once('vendor/stripe/stripe-php/init.php');
     $this->createPaymentProcessor();
     $this->createContact();
     $this->created_ts = time();
   }
 
-  public function tearDown() {
+  public function tearDown(): void {
+    civicrm_api3('PaymentProcessor', 'delete', ['id' => $this->paymentProcessorID]);
+    civicrm_api3('Extension', 'disable', ['keys' => 'com.drastikbydesign.stripe']);
+    civicrm_api3('Extension', 'uninstall', ['keys' => 'com.drastikbydesign.stripe']);
     parent::tearDown();
   }
 
+  /**
+   *
+   */
+  protected function returnValueMapOrDie($map): ValueMapOrDie {
+    return new ValueMapOrDie($map);
+  }
+
   /**
    * Create contact.
    */
diff --git a/tests/phpunit/CRM/Stripe/DirectTest.php b/tests/phpunit/CRM/Stripe/DirectTest.php
index 1c52085dac1ce70d4e009a67eb94c1360b655bad..4440062c760a2b6e29b8f2e2633f0327b5f2619e 100644
--- a/tests/phpunit/CRM/Stripe/DirectTest.php
+++ b/tests/phpunit/CRM/Stripe/DirectTest.php
@@ -9,32 +9,18 @@
  +--------------------------------------------------------------------+
  */
 
-use Civi\Test\HeadlessInterface;
-use Civi\Test\HookInterface;
-use Civi\Test\TransactionalInterface;
-
 /**
  * Test a simple, direct payment via Stripe. 
  *
  * @group headless
  */
-require ('BaseTest.php');
 class CRM_Stripe_DirectTest extends CRM_Stripe_BaseTest {
 
-  public function setUpHeadless() {
-    // Civi\Test has many helpers, like install(), uninstall(), sql(), and sqlFile().
-    // See: https://github.com/civicrm/org.civicrm.testapalooza/blob/master/civi-test.md
-    return \Civi\Test::headless()
-      ->install('mjwshared')
-      ->installMe(__DIR__)
-      ->apply();
-  }
-
-  public function setUp() {
+  public function setUp(): void {
     parent::setUp();
   }
 
-  public function tearDown() {
+  public function tearDown(): void {
     parent::tearDown();
   }
 
diff --git a/tests/phpunit/CRM/Stripe/IpnTest.php b/tests/phpunit/CRM/Stripe/IpnTest.php
index aaeb276283116b16f93d0c517d2960211e93e391..8844ba96074b09a42b4de542f20307be9daec2d8 100644
--- a/tests/phpunit/CRM/Stripe/IpnTest.php
+++ b/tests/phpunit/CRM/Stripe/IpnTest.php
@@ -27,16 +27,11 @@
  *
  */
 
-use Civi\Test\HeadlessInterface;
-use Civi\Test\HookInterface;
-use Civi\Test\TransactionalInterface;
-
 /**
  * Tests simple recurring contribution with IPN.
  *
  * @group headless
  */
-require ('BaseTest.php');
 class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
   protected $contributionRecurID;
   protected $installments = 5;
@@ -44,16 +39,6 @@ class CRM_Stripe_IpnTest extends CRM_Stripe_BaseTest {
   protected $frequency_interval = 1;
   protected $created_ts;
 
-  // This test is particularly dirty for some reason so we have to
-  // force a reset.
-  public function setUpHeadless() {
-    $force = FALSE;
-    return \Civi\Test::headless()
-      ->install('mjwshared')
-      ->installMe(__DIR__)
-      ->apply($force);
-  }
-
   /**
    * Test creating a recurring contribution and
    * update it after creation. @todo The membership should also be updated.
@@ -1238,7 +1223,9 @@ class PropertySpy implements ArrayAccess, Iterator, Countable, JsonSerializable
 /**
  * Stubs a method by returning a value from a map.
  */
-class ValueMapOrDie implements \PHPUnit\Framework\MockObject\Stub {
+class ValueMapOrDie implements \PHPUnit\Framework\MockObject\Stub\Stub {
+
+  use \PHPUnit\Framework\MockObject\Api;
 
   protected $valueMap;
 
diff --git a/tests/phpunit/bootstrap.php b/tests/phpunit/bootstrap.php
index 419b92dd9b284aa6f69e8e6cd470fe644d968515..58e22748cac42c088f24c8baa8c0fb4924ede302 100644
--- a/tests/phpunit/bootstrap.php
+++ b/tests/phpunit/bootstrap.php
@@ -10,9 +10,9 @@
  */
 
 ini_set('memory_limit', '2G');
-ini_set('safe_mode', 0);
+define('CIVICRM_TEST', 1);
 // phpcs:ignore
-eval(cv('php:boot --level=classloader', 'phpcode'));
+eval(cv('php:boot --level=settings', 'phpcode'));
 
 // Allow autoloading of PHPUnit helper classes in this extension.
 $loader = new \Composer\Autoload\ClassLoader();
@@ -22,6 +22,10 @@ $loader->add('api_', __DIR__);
 $loader->add('api\\', __DIR__);
 $loader->register();
 
+if (CIVICRM_UF === 'UnitTests') {
+  Civi\Test::headless()->apply();
+}
+
 /**
  * Call the "cv" command.
  *
@@ -42,7 +46,9 @@ function cv($cmd, $decode = 'json') {
 
   // Execute `cv` in the original folder. This is a work-around for
   // phpunit/codeception, which seem to manipulate PWD.
-  $cmd = sprintf('cd %s; %s', escapeshellarg(getenv('PWD')), $cmd);
+  if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
+    $cmd = sprintf('cd %s; %s', escapeshellarg(getenv('PWD')), $cmd);
+  }
 
   $process = proc_open($cmd, $descriptorSpec, $pipes, __DIR__);
   putenv("CV_OUTPUT=$oldOutput");