You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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,禁用失败后终止逻辑:
    #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); // 预期该测试失败
    }
    
    注意:此时需要修改CMake配置,将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 13:54:56