使用Emscripten编译时,Catch2测试失败导致测试套件崩溃
问题:Emscripten编译的Catch2测试失败时崩溃抛出
Catch::TestFailureException 我有一个通过Emscripten编译为WebAssembly的C++项目,想用Catch2运行测试,但测试失败时,测试套件不会输出完整的失败日志,直接崩溃并抛出Catch::TestFailureException。
可复现的测试代码
#include <catch2/catch_test_macros.hpp> TEST_CASE("Foo","Bar") { REQUIRE(1 == 2); // 预期该测试失败 }
主项目CMakeLists.txt配置
cmake_minimum_required(VERSION 3.28) project(HelloEmscripten) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) Include(FetchContent) FetchContent_Declare( Catch2 GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v3.4.0 # or a later release ) FetchContent_MakeAvailable(Catch2) list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras) add_subdirectory(test)
测试目录CMakeLists.txt配置
add_executable(unit_tests test.cpp) target_link_libraries(unit_tests PRIVATE Catch2::Catch2WithMain) include(Catch) catch_discover_tests(unit_tests) if(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten") target_link_options(unit_tests PRIVATE -fexceptions) target_compile_options(unit_tests PRIVATE -fexceptions) endif()
运行输出
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ unit_tests is a Catch2 v3.4.0 host application. Run with -? for options ------------------------------------------------------------------------------- Foo ------------------------------------------------------------------------------- ~/workshop/cpp/tutorials/emscripten/source/test/test.cpp:3 ............................................................................... ~/workshop/cpp/tutorials/emscripten/source/test/test.cpp:4: FAILED: REQUIRE( 1 == 2 ) ~/workshop/cpp/tutorials/emscripten/build/test/unit_tests.js:1242 exceptionLast = new CppException(ptr); ^ Catch::TestFailureException at ___cxa_throw (~/workshop/cpp/tutorials/emscripten/build/test/unit_tests.js:1242:23) at wasm://wasm/005ded6e:wasm-function[6608]:0xcf671 at wasm://wasm/005ded6e:wasm-function[478]:0xdc52 at invoke_vi (~/workshop/cpp/tutorials/emscripten/build/test/unit_tests.js:4646:29) at wasm://wasm/005ded6e:wasm-function[56]:0x4c1f at wasm://wasm/005ded6e:wasm-function[6637]:0xd0386 at wasm://wasm/005ded6e:wasm-function[5043]:0x9c8c1 at wasm://wasm/005ded6e:wasm-function[4946]:0x988ef at wasm://wasm/005ded6e:wasm-function[4942]:0x98601 at wasm://wasm/005ded6e:wasm-function[4938]:0x97c78 { excPtr: 136168 }
个人观察
- 不使用Emscripten编译时,直接运行
./test/unit_test无此问题 - 测试全部通过时,能正常运行完成
- 已尝试通过
target_xxx_options加-fexceptions、改用-fwasm-exceptions、设置CMAKE_CXX_FLAGS "-s DISABLE_EXCEPTION_CATCHING=0",问题仍存在
解决方案
这个问题的核心是Emscripten环境中,Catch2默认的异常处理逻辑未被正确捕获,导致异常逃出测试框架触发JS层崩溃。可通过以下步骤解决:
1. 完善Emscripten异常捕获配置
在测试目录的CMakeLists.txt中,补充Emscripten特定的链接选项,确保异常能被正常捕获:
if(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten") target_compile_options(unit_tests PRIVATE -fexceptions) target_link_options(unit_tests PRIVATE -fexceptions -s DISABLE_EXCEPTION_CATCHING=0 -s EXCEPTION_DEBUG=1 # 可选,用于调试异常细节 ) endif()
DISABLE_EXCEPTION_CATCHING=0是关键,它强制Emscripten允许C++异常被捕获,而非直接终止程序。
2. 调整Catch2的失败后行为
Catch2默认在测试失败后终止进程,在Emscripten环境中会导致异常逃逸。可通过两种方式修改:
- 命令行参数:运行测试时添加
--no-abort选项node ./test/unit_tests --no-abort - 自定义main函数:在测试代码中添加自定义main,禁用失败后终止逻辑:
注意:此时需要修改CMake配置,将#include <catch2/catch_test_macros.hpp> #include <catch2/catch_session.hpp> int main(int argc, char* argv[]) { Catch::Session session; // 禁用失败后自动终止 session.configData().abortAfterFailure = false; return session.run(argc, argv); } TEST_CASE("Foo","Bar") { REQUIRE(1 == 2); // 预期该测试失败 }Catch2::Catch2WithMain替换为Catch2::Catch2:target_link_libraries(unit_tests PRIVATE Catch2::Catch2)
3. 验证结果
修改后重新编译运行,即可看到完整的测试失败报告,不会再抛出未捕获的Catch::TestFailureException,示例输出如下:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ unit_tests is a Catch2 v3.4.0 host application. Run with -? for options ------------------------------------------------------------------------------- Foo ------------------------------------------------------------------------------- ~/workshop/cpp/tutorials/emscripten/source/test/test.cpp:10 ............................................................................... ~/workshop/cpp/tutorials/emscripten/source/test/test.cpp:11: FAILED: REQUIRE( 1 == 2 ) with expansion: 1 == 2 =============================================================================== test cases: 1 | 1 failed assertions: 1 | 1 failed
内容的提问来源于stack exchange,提问作者lawsumisu
相关产品推荐
相关产品推荐

