diff --git .gitignore .gitignore
index f26f47fbd..cc3f92c79 100644
--- .gitignore
+++ .gitignore
@@ -23,3 +23,6 @@ npm-debug.log
 
 # The build directory.
 build
+
+# The custom Docker config file.
+.wp-env.override.json
diff --git .wp-env.json .wp-env.json
new file mode 100644
index 000000000..5bbdc60b5
--- /dev/null
+++ .wp-env.json
@@ -0,0 +1,8 @@
+{
+	"core": "WordPress/WordPress#master",
+	"plugins": [ ".", "buddypress/BP-REST#master" ],
+	"config": {
+		"WP_DEBUG": true,
+		"SCRIPT_DEBUG": true
+	}
+}
diff --git composer.json composer.json
index 216b1d8a6..d07167858 100644
--- composer.json
+++ composer.json
@@ -32,6 +32,7 @@
 	},
 	"require-dev": {
 		"phpcompatibility/phpcompatibility-wp": "*",
-		"dealerdirect/phpcodesniffer-composer-installer": "^0.4.3"
+		"dealerdirect/phpcodesniffer-composer-installer": "^0.4.3",
+		"wp-phpunit/wp-phpunit": "^5.4"
 	}
 }
diff --git package.json package.json
index 93e123039..09f321716 100644
--- package.json
+++ package.json
@@ -8,6 +8,7 @@
 		"@babel/core": "~7.8.7",
 		"@wordpress/babel-preset-default": "~4.10.0",
 		"@wordpress/browserslist-config": "~2.1.4",
+		"@wordpress/env": "~1.6.0",
 		"autoprefixer": "~8.5.2",
 		"grunt": "~1.1.0",
 		"grunt-check-dependencies": "~1.0.0",
@@ -44,7 +45,10 @@
 		"build": "npm run build:components && parcel build src/js/bp-*/*s/blocks/*.js --out-dir build",
 		"watch:components": "parcel watch src/js/bp-core/js/block-components/block-components.js --out-dir src/bp-core/js --out-file block-components.js --no-source-maps --global bp",
 		"dev:components": "parcel build src/js/bp-core/js/block-components/block-components.js --out-dir src/bp-core/js --out-file block-components.js --no-source-maps --no-minify --global bp",
-		"build:components": "parcel build src/js/bp-core/js/block-components/block-components.js --out-dir build/bp-core/js --out-file block-components.js --global bp"
+		"build:components": "parcel build src/js/bp-core/js/block-components/block-components.js --out-dir build/bp-core/js --out-file block-components.js --global bp",
+		"wp-env": "wp-env",
+		"test-php": "npm run wp-env run phpunit 'phpunit -c /var/www/html/wp-content/plugins/buddypress/tests/phpunit/env.xml'",
+		"test-php-multisite": "npm run wp-env run phpunit 'phpunit -c /var/www/html/wp-content/plugins/buddypress/tests/phpunit/env.multisite.xml'"
 	},
 	"keywords": [
 		"activity",
diff --git tests/phpunit/assets/phpunit-wp-config.php tests/phpunit/assets/phpunit-wp-config.php
new file mode 100644
index 000000000..5113dd55b
--- /dev/null
+++ tests/phpunit/assets/phpunit-wp-config.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * The base configuration for WordPress
+ *
+ * The wp-config.php creation script uses this file during the
+ * installation. You don't have to use the web site, you can
+ * copy this file to "wp-config.php" and fill in the values.
+ *
+ * This file contains the following configurations:
+ *
+ * * MySQL settings
+ * * Secret keys
+ * * Database table prefix
+ * * ABSPATH
+ *
+ * @link https://wordpress.org/support/article/editing-wp-config-php/
+ *
+ * @package WordPress
+ */
+
+// ** MySQL settings - You can get this info from your web host ** //
+/** The name of the database for WordPress */
+define( 'DB_NAME', 'tests-wordpress');
+
+/** MySQL database username */
+define( 'DB_USER', 'root');
+
+/** MySQL database password */
+define( 'DB_PASSWORD', '');
+
+/** MySQL hostname */
+define( 'DB_HOST', 'mysql');
+
+/** Database Charset to use in creating database tables. */
+define( 'DB_CHARSET', 'utf8');
+
+/** The Database Collate type. Don't change this if in doubt. */
+define( 'DB_COLLATE', '');
+
+/**#@+
+ * Authentication Unique Keys and Salts.
+ *
+ * Change these to different unique phrases!
+ * You can generate these using the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}
+ * You can change these at any point in time to invalidate all existing cookies. This will force all users to have to log in again.
+ *
+ * @since 2.6.0
+ */
+define( 'AUTH_KEY',         'a89b7f2679fa896912a0bc6663b8c1dee8845e0e');
+define( 'SECURE_AUTH_KEY',  '0819cb8ebad69f537adc5351b095a91e3fee5fbd');
+define( 'LOGGED_IN_KEY',    'ea0ab2035e22b76f751a44df6a89d85c44f9ba1f');
+define( 'NONCE_KEY',        '4665de6759a3f771be0509b8964c0dee8b12cc3e');
+define( 'AUTH_SALT',        'cd8ff2945b6e3bf3257845f6f1c14de673f38bb1');
+define( 'SECURE_AUTH_SALT', 'd9c8a7a96d41e863c0e8517632e0d4f1ab135d49');
+define( 'LOGGED_IN_SALT',   '318a8828a24ea9fa51d10a0aabb92d419c716e3e');
+define( 'NONCE_SALT',       '08e12a5848e0f7516e1b527497239c41f55904ab');
+
+/**#@-*/
+
+/**
+ * WordPress Database Table prefix.
+ *
+ * You can have multiple installations in one database if you give each
+ * a unique prefix. Only numbers, letters, and underscores please!
+ */
+$table_prefix = 'wptests_';
+
+/**
+ * Test with WordPress debug mode (default).
+ */
+define( 'WP_DEBUG', true );
+
+// Set Site domain, email and title constants.
+define( 'WP_TESTS_DOMAIN', 'example.org' );
+define( 'WP_TESTS_EMAIL', 'admin@example.org' );
+define( 'WP_TESTS_TITLE', 'Test BP' );
+
+define( 'WP_PHP_BINARY', 'php' );
+
+/** Absolute path to the WordPress directory. */
+if ( ! defined( 'ABSPATH' ) ) {
+        define( 'ABSPATH', '/var/www/html/' );
+}
diff --git tests/phpunit/bootstrap.php tests/phpunit/bootstrap.php
index 4e517f9ab..18097fc1e 100644
--- tests/phpunit/bootstrap.php
+++ tests/phpunit/bootstrap.php
@@ -1,5 +1,14 @@
 <?php
 
+if ( defined( 'BP_USE_WP_ENV_TESTS' ) ) {
+	// wp-env setup.
+	define( 'WP_TESTS_CONFIG_FILE_PATH', dirname( __FILE__ ) . '/assets/phpunit-wp-config.php' );
+	define( 'WP_TESTS_CONFIG_PATH', WP_TESTS_CONFIG_FILE_PATH );
+
+	// Use WP PHPUnit.
+	require_once dirname( dirname( dirname( __FILE__ ) ) ) . '/vendor/wp-phpunit/wp-phpunit/__loaded.php';
+}
+
 require( dirname( __FILE__ ) . '/includes/define-constants.php' );
 
 if ( ! file_exists( WP_TESTS_DIR . '/includes/functions.php' ) ) {
diff --git tests/phpunit/env.multisite.xml tests/phpunit/env.multisite.xml
new file mode 100644
index 000000000..e40b4b6ff
--- /dev/null
+++ tests/phpunit/env.multisite.xml
@@ -0,0 +1,18 @@
+<phpunit
+	bootstrap="bootstrap.php"
+	backupGlobals="false"
+	colors="true"
+	convertErrorsToExceptions="true"
+	convertNoticesToExceptions="true"
+	convertWarningsToExceptions="true"
+	>
+	<php>
+		<const name="WP_TESTS_MULTISITE" value="1" />
+		<const name="BP_USE_WP_ENV_TESTS" value="1" />
+	</php>
+	<testsuites>
+		<testsuite name="default">
+			<directory suffix=".php">./testcases/</directory>
+		</testsuite>
+	</testsuites>
+</phpunit>
diff --git tests/phpunit/env.xml tests/phpunit/env.xml
new file mode 100644
index 000000000..314564af1
--- /dev/null
+++ tests/phpunit/env.xml
@@ -0,0 +1,17 @@
+<phpunit
+	bootstrap="bootstrap.php"
+	backupGlobals="false"
+	colors="true"
+	convertErrorsToExceptions="true"
+	convertNoticesToExceptions="true"
+	convertWarningsToExceptions="true"
+	>
+	<php>
+		<const name="BP_USE_WP_ENV_TESTS" value="1" />
+	</php>
+	<testsuites>
+		<testsuite name="default">
+			<directory suffix=".php">./testcases/</directory>
+		</testsuite>
+	</testsuites>
+</phpunit>
diff --git tests/phpunit/includes/define-constants.php tests/phpunit/includes/define-constants.php
index 1b4e0e9d9..a2805a73a 100644
--- tests/phpunit/includes/define-constants.php
+++ tests/phpunit/includes/define-constants.php
@@ -20,7 +20,10 @@ if ( ! defined( 'BP_TESTS_DIR' ) ) {
  * - Assume that we are inside of a develop.svn.wordpress.org setup, and walk
  *   up the directory tree
  */
-if ( false !== getenv( 'WP_TESTS_DIR' ) ) {
+if ( false !== getenv( 'WP_PHPUNIT__DIR' ) ) {
+	define( 'WP_TESTS_DIR', getenv( 'WP_PHPUNIT__DIR' ) );
+	define( 'WP_ROOT_DIR', '/var/www/html' );
+} elseif ( false !== getenv( 'WP_TESTS_DIR' ) ) {
 	define( 'WP_TESTS_DIR', getenv( 'WP_TESTS_DIR' ) );
 	define( 'WP_ROOT_DIR', WP_TESTS_DIR );
 } else {
@@ -34,20 +37,22 @@ if ( false !== getenv( 'WP_TESTS_DIR' ) ) {
 	define( 'WP_TESTS_DIR', WP_ROOT_DIR . '/tests/phpunit' );
 }
 
-// Based on the tests directory, look for a config file
-if ( file_exists( WP_ROOT_DIR . '/wp-tests-config.php' ) ) {
-	// Standard develop.svn.wordpress.org setup
-	define( 'WP_TESTS_CONFIG_PATH', WP_ROOT_DIR . '/wp-tests-config.php' );
+if ( ! defined( 'WP_TESTS_CONFIG_FILE_PATH' ) ) {
+	// Based on the tests directory, look for a config file
+	if ( file_exists( WP_ROOT_DIR . '/wp-tests-config.php' ) ) {
+		// Standard develop.svn.wordpress.org setup
+		define( 'WP_TESTS_CONFIG_PATH', WP_ROOT_DIR . '/wp-tests-config.php' );
 
-} elseif ( file_exists( WP_TESTS_DIR . '/wp-tests-config.php' ) ) {
-	// Legacy unit-test.svn.wordpress.org setup
-	define( 'WP_TESTS_CONFIG_PATH', WP_TESTS_DIR . '/wp-tests-config.php' );
+	} elseif ( file_exists( WP_TESTS_DIR . '/wp-tests-config.php' ) ) {
+		// Legacy unit-test.svn.wordpress.org setup
+		define( 'WP_TESTS_CONFIG_PATH', WP_TESTS_DIR . '/wp-tests-config.php' );
 
-} elseif ( file_exists( dirname( dirname( WP_TESTS_DIR ) ) . '/wp-tests-config.php' ) ) {
-	// Environment variable exists and points to tests/phpunit of
-	// develop.svn.wordpress.org setup
-	define( 'WP_TESTS_CONFIG_PATH', dirname( dirname( WP_TESTS_DIR ) ) . '/wp-tests-config.php' );
+	} elseif ( file_exists( dirname( dirname( WP_TESTS_DIR ) ) . '/wp-tests-config.php' ) ) {
+		// Environment variable exists and points to tests/phpunit of
+		// develop.svn.wordpress.org setup
+		define( 'WP_TESTS_CONFIG_PATH', dirname( dirname( WP_TESTS_DIR ) ) . '/wp-tests-config.php' );
 
-} else {
-	die( "wp-tests-config.php could not be found.\n" );
+	} else {
+		die( "wp-tests-config.php could not be found.\n" );
+	}
 }
diff --git tests/phpunit/includes/loader.php tests/phpunit/includes/loader.php
index df7dc0b5f..db083bb0b 100644
--- tests/phpunit/includes/loader.php
+++ tests/phpunit/includes/loader.php
@@ -37,4 +37,4 @@ foreach ( $components as $component ) {
 			}
 		}
 	} );
-}
\ No newline at end of file
+}
