diff --git a/cmake/modules/TestSuite.cmake b/cmake/modules/TestSuite.cmake
--- a/cmake/modules/TestSuite.cmake
+++ b/cmake/modules/TestSuite.cmake
@@ -1,9 +1,11 @@
 # Allow to easily build test suites
 
 macro(create_test_suite NAME)
-	enable_testing()
 	set(TARGET "check-${NAME}")
-	add_custom_target(${TARGET} COMMAND ${CMAKE_CTEST_COMMAND})
+	add_custom_target(${TARGET}
+		COMMENT "Running ${NAME} test suite"
+		COMMAND cmake -E echo "PASSED: ${NAME} test suite"
+	)
 
 	# If the magic target check-all exists, attach to it.
 	if(TARGET check-all)
@@ -11,14 +13,53 @@
 	endif()
 endmacro(create_test_suite)
 
+set(TEST_RUNNER_TEMPLATE "${CMAKE_CURRENT_LIST_DIR}/../templates/TestRunner.cmake.in")
+function(_add_test_runner SUITE NAME COMMAND)
+	set(TARGET "test-${NAME}")
+	set(LOG "${NAME}.log")
+	set(RUNNER "${CMAKE_CURRENT_BINARY_DIR}/run-${NAME}.sh")
+	list(JOIN ARGN " " ARGS)
+
+	configure_file(
+		"${TEST_RUNNER_TEMPLATE}"
+		"${RUNNER}"
+	)
+
+	add_custom_target(${TARGET}
+		COMMAND ${RUNNER}
+		COMMENT "${SUITE}: testing ${NAME}"
+		DEPENDS
+			${COMMAND}
+			${RUNNER}
+	)
+	add_dependencies("check-${SUITE}" ${TARGET})
+endfunction()
+
 function(add_test_to_suite SUITE NAME)
 	add_executable(${NAME} EXCLUDE_FROM_ALL ${ARGN})
-	add_test(${NAME} ${NAME})
-	add_dependencies("check-${SUITE}" ${NAME})
+	_add_test_runner(${SUITE} ${NAME} ${NAME})
 endfunction(add_test_to_suite)
 
 function(add_boost_unit_tests_to_suite SUITE NAME)
-	add_test_to_suite(${SUITE} ${NAME} ${ARGN})
+	cmake_parse_arguments(ARG
+		""
+		""
+		"TESTS"
+		${ARGN}
+	)
+
+	add_executable(${NAME} EXCLUDE_FROM_ALL ${ARG_UNPARSED_ARGUMENTS})
+	add_dependencies("check-${SUITE}" ${NAME})
+
+	foreach(_test_source ${ARG_TESTS})
+		target_sources(${NAME} PRIVATE "${_test_source}")
+		get_filename_component(_test_name "${_test_source}" NAME_WE)
+		_add_test_runner(
+			${SUITE}
+			${_test_name}
+			${NAME} -t "${_test_name}"
+		)
+	endforeach()
 
 	find_package(Boost 1.58 REQUIRED unit_test_framework)
 	target_link_libraries(${NAME} Boost::unit_test_framework)
diff --git a/cmake/templates/TestRunner.cmake.in b/cmake/templates/TestRunner.cmake.in
new file mode 100755
--- /dev/null
+++ b/cmake/templates/TestRunner.cmake.in
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+"./${COMMAND}" ${ARGS} > "${LOG}" 2>&1 || (cat "${LOG}" && exit 1)
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
--- a/src/test/CMakeLists.txt
+++ b/src/test/CMakeLists.txt
@@ -46,112 +46,114 @@
 add_dependencies(check check-bitcoin)
 
 add_boost_unit_tests_to_suite(bitcoin test_bitcoin
-	activation_tests.cpp
-	addrman_tests.cpp
-	allocator_tests.cpp
-	amount_tests.cpp
-	arith_uint256_tests.cpp
-	avalanche_tests.cpp
-	base32_tests.cpp
-	base58_tests.cpp
-	base64_tests.cpp
-	bip32_tests.cpp
-	bitmanip_tests.cpp
-	blockchain_tests.cpp
-	blockcheck_tests.cpp
-	blockencodings_tests.cpp
-	blockfilter_tests.cpp
-	blockindex_tests.cpp
-	blockstatus_tests.cpp
-	bloom_tests.cpp
-	bswap_tests.cpp
-	cashaddr_tests.cpp
-	cashaddrenc_tests.cpp
-	checkdatasig_tests.cpp
-	checkpoints_tests.cpp
-	checkqueue_tests.cpp
-	coins_tests.cpp
-	compress_tests.cpp
-	config_tests.cpp
-	core_io_tests.cpp
-	crypto_tests.cpp
-	cuckoocache_tests.cpp
-	dbwrapper_tests.cpp
-	denialofservice_tests.cpp
-	descriptor_tests.cpp
-	dstencode_tests.cpp
-	excessiveblock_tests.cpp
-	feerate_tests.cpp
-	finalization_tests.cpp
-	flatfile_tests.cpp
-	getarg_tests.cpp
-	hash_tests.cpp
-	inv_tests.cpp
 	jsonutil.cpp
-	key_io_tests.cpp
-	key_tests.cpp
-	lcg_tests.cpp
-	limitedmap_tests.cpp
-	mempool_tests.cpp
-	merkle_tests.cpp
-	merkleblock_tests.cpp
-	miner_tests.cpp
-	monolith_opcodes_tests.cpp
-	multisig_tests.cpp
-	net_tests.cpp
-	netbase_tests.cpp
-	pmt_tests.cpp
-	policyestimator_tests.cpp
-	pow_tests.cpp
-	prevector_tests.cpp
-	radix_tests.cpp
-	raii_event_tests.cpp
-	random_tests.cpp
-	rcu_tests.cpp
-	reverselock_tests.cpp
-	rpc_tests.cpp
-	rpc_server_tests.cpp
-	rwcollection_tests.cpp
-	sanity_tests.cpp
-	scheduler_tests.cpp
-	schnorr_tests.cpp
-	script_bitfield_tests.cpp
-	script_commitment_tests.cpp
-	script_p2sh_tests.cpp
-	script_standard_tests.cpp
-	script_tests.cpp
 	scriptflags.cpp
-	scriptnum_tests.cpp
-	serialize_tests.cpp
-	sigcache_tests.cpp
-	sigencoding_tests.cpp
-	sighash_tests.cpp
-	sighashtype_tests.cpp
-	sigopcount_tests.cpp
 	sigutil.cpp
-	skiplist_tests.cpp
-	streams_tests.cpp
-	sync_tests.cpp
 	test_bitcoin.cpp
 	test_bitcoin_main.cpp
-	timedata_tests.cpp
-	torcontrol_tests.cpp
-	transaction_tests.cpp
-	txindex_tests.cpp
-	txvalidation_tests.cpp
-	txvalidationcache_tests.cpp
-	uint256_tests.cpp
-	undo_tests.cpp
-	util_tests.cpp
-	validation_block_tests.cpp
-	validation_tests.cpp
-	work_comparator_tests.cpp
-
-	# RPC Tests
-	../rpc/test/server_tests.cpp
 
 	# Tests generated from JSON
 	${JSON_HEADERS}
+
+	TESTS
+		activation_tests.cpp
+		addrman_tests.cpp
+		allocator_tests.cpp
+		amount_tests.cpp
+		arith_uint256_tests.cpp
+		avalanche_tests.cpp
+		base32_tests.cpp
+		base58_tests.cpp
+		base64_tests.cpp
+		bip32_tests.cpp
+		bitmanip_tests.cpp
+		blockchain_tests.cpp
+		blockcheck_tests.cpp
+		blockencodings_tests.cpp
+		blockfilter_tests.cpp
+		blockindex_tests.cpp
+		blockstatus_tests.cpp
+		bloom_tests.cpp
+		bswap_tests.cpp
+		cashaddr_tests.cpp
+		cashaddrenc_tests.cpp
+		checkdatasig_tests.cpp
+		checkpoints_tests.cpp
+		checkqueue_tests.cpp
+		coins_tests.cpp
+		compress_tests.cpp
+		config_tests.cpp
+		core_io_tests.cpp
+		crypto_tests.cpp
+		cuckoocache_tests.cpp
+		dbwrapper_tests.cpp
+		denialofservice_tests.cpp
+		descriptor_tests.cpp
+		dstencode_tests.cpp
+		excessiveblock_tests.cpp
+		feerate_tests.cpp
+		finalization_tests.cpp
+		flatfile_tests.cpp
+		getarg_tests.cpp
+		hash_tests.cpp
+		inv_tests.cpp
+		key_io_tests.cpp
+		key_tests.cpp
+		lcg_tests.cpp
+		limitedmap_tests.cpp
+		mempool_tests.cpp
+		merkle_tests.cpp
+		merkleblock_tests.cpp
+		miner_tests.cpp
+		monolith_opcodes_tests.cpp
+		multisig_tests.cpp
+		net_tests.cpp
+		netbase_tests.cpp
+		pmt_tests.cpp
+		policyestimator_tests.cpp
+		pow_tests.cpp
+		prevector_tests.cpp
+		radix_tests.cpp
+		raii_event_tests.cpp
+		random_tests.cpp
+		rcu_tests.cpp
+		reverselock_tests.cpp
+		rpc_tests.cpp
+		rpc_server_tests.cpp
+		rwcollection_tests.cpp
+		sanity_tests.cpp
+		scheduler_tests.cpp
+		schnorr_tests.cpp
+		script_bitfield_tests.cpp
+		script_commitment_tests.cpp
+		script_p2sh_tests.cpp
+		script_standard_tests.cpp
+		script_tests.cpp
+		scriptnum_tests.cpp
+		serialize_tests.cpp
+		sigcache_tests.cpp
+		sigencoding_tests.cpp
+		sighash_tests.cpp
+		sighashtype_tests.cpp
+		sigopcount_tests.cpp
+		skiplist_tests.cpp
+		streams_tests.cpp
+		sync_tests.cpp
+		timedata_tests.cpp
+		torcontrol_tests.cpp
+		transaction_tests.cpp
+		txindex_tests.cpp
+		txvalidation_tests.cpp
+		txvalidationcache_tests.cpp
+		uint256_tests.cpp
+		undo_tests.cpp
+		util_tests.cpp
+		validation_block_tests.cpp
+		validation_tests.cpp
+		work_comparator_tests.cpp
+
+		# RPC Tests
+		../rpc/test/server_tests.cpp
 )
 
 if (TEST_WITH_UPGRADE_ACTIVATED)