最最最重要的是,在重构RHI测试的过程中,如果发现了RHI模块设计上的根本问题,需要紧急向我汇报!!!!!!!! # RHI 模块单元测试重构计划 ## 1. 项目背景 本文档分析 XCEngine RHI(渲染硬件抽象层)模块的三个单元测试层次的覆盖度和质量问题,并提出重构建议。 ### 1.1 测试层次结构 | 层次 | 位置 | 测试数量 | 特点 | |------|------|----------|------| | **RHI 抽象层** | `tests/RHI/unit/` | 75 tests × 2 backends = 150 | 参数化测试,跨 D3D12/OpenGL | | **D3D12 后端** | `tests/RHI/D3D12/unit/` | ~58 tests | 非参数化,直接测试 D3D12 API | | **OpenGL 后端** | `tests/RHI/OpenGL/unit/` | ~58 tests | 非参数化,直接测试 OpenGL API | ### 1.2 当前测试文件分布 #### RHI 抽象层 (`tests/RHI/unit/`) | 文件 | 测试数 | 测试类 | |------|--------|--------| | `test_device.cpp` | 8 | RHIDevice | | `test_buffer.cpp` | 8 | RHIBuffer | | `test_texture.cpp` | 5 | RHITexture | | `test_swap_chain.cpp` | 4 | RHISwapChain | | `test_command_list.cpp` | 14 | RHICommandList | | `test_command_queue.cpp` | 6 | RHICommandQueue | | `test_shader.cpp` | 7 | RHIShader | | `test_fence.cpp` | 10 | RHIFence | | `test_sampler.cpp` | 4 | RHISampler | | `test_factory.cpp` | 5 | RHIFactory | | `test_pipeline_state.cpp` | 10 | RHIPipelineState | | `test_render_pass.cpp` | 10 | RHIRenderPass | | `test_framebuffer.cpp` | 8 | RHIFramebuffer | | `test_compute.cpp` | 8 | Compute/Dispatch | #### D3D12 后端 (`tests/RHI/D3D12/unit/`) | 文件 | 测试数 | 测试类/功能 | |------|--------|-------------| | `test_device.cpp` | 6 | D3D12Device | | `test_fence.cpp` | 9 | D3D12Fence | | `test_command_queue.cpp` | 2 | D3D12CommandQueue | | `test_command_allocator.cpp` | 3 | D3D12CommandAllocator | | `test_command_list.cpp` | 2 | D3D12CommandList | | `test_buffer.cpp` | 6 | D3D12Buffer | | `test_texture.cpp` | 4 | D3D12Texture | | `test_descriptor_heap.cpp` | 9 | D3D12DescriptorHeap | | `test_shader.cpp` | 3 | D3D12Shader (trivial) | | `test_root_signature.cpp` | 2 | D3D12RootSignature | | `test_pipeline_state.cpp` | 2 | D3D12 PSO (trivial) | | `test_views.cpp` | 4 | RTV/DSV/CBV | | `test_swap_chain.cpp` | 5 | D3D12SwapChain | #### OpenGL 后端 (`tests/RHI/OpenGL/unit/`) | 文件 | 测试数 | 测试类/功能 | |------|--------|-------------| | `test_device.cpp` | 2 | OpenGLDevice | | `test_buffer.cpp` | 6 | OpenGLBuffer | | `test_fence.cpp` | 8 | OpenGLFence | | `test_texture.cpp` | 5 | OpenGLTexture | | `test_shader.cpp` | 4 | OpenGLShader | | `test_pipeline_state.cpp` | 3 | OpenGLPipelineState | | `test_vertex_array.cpp` | 5 | OpenGLVertexArray | | `test_command_list.cpp` | 9 | OpenGLCommandList | | `test_render_target_view.cpp` | 4 | OpenGLRenderTargetView | | `test_depth_stencil_view.cpp` | 4 | OpenGLDepthStencilView | | `test_swap_chain.cpp` | 3 | OpenGLSwapChain | | `test_sampler.cpp` | 4 | OpenGLSampler | --- ## 2. 严重问题(P0 - 必须修复) ### 2.1 `tests/RHI/unit/test_shader.cpp` - 9个测试完全相同 ✅ 已修复 **状态**: ✅ 已完成 (2026-03-25) **修复内容**: 1. **Shader 编译抽象重构** - 扩展 `ShaderCompileDesc` 支持内嵌源码: ```cpp struct ShaderCompileDesc { std::wstring fileName; // 文件路径(可选) std::vector source; // 内嵌源码(可选) ShaderLanguage sourceLanguage; // 源码语言:HLSL/GLSL/SPIRV std::wstring entryPoint; // Entry point 名称 std::wstring profile; // Profile std::vector macros; }; ``` 2. **新增 `ShaderLanguage` 枚举**: ```cpp enum class ShaderLanguage : uint8_t { Unknown, HLSL, // D3D11/D3D12 GLSL, // OpenGL/Vulkan SPIRV // Vulkan (pre-compiled) }; ``` 3. **测试重构** - 9个相同测试 → 7个有效测试: - `Shader_Compile_EmptyDesc_ReturnsNullptr` - 空描述符测试 - `Shader_Compile_ValidVertexShader` - 顶点着色器编译测试 - `Shader_Compile_ValidFragmentShader` - 片段着色器编译测试 - `Shader_GetType_VertexShader` - 获取顶点着色器类型 - `Shader_GetType_FragmentShader` - 获取片段着色器类型 - `Shader_GetNativeHandle_ValidShader` - 获取原生句柄 - `Shader_Shutdown_Invalidates` - 关闭后验证失效 **测试结果**: 14/14 通过 (D3D12: 7, OpenGL: 7) --- ### 2.2 关键 RHI 抽象类完全没有测试 **严重程度**: 🔴 致命 **问题描述**: 以下 RHI 抽象类在 `tests/RHI/unit/` 中完全没有测试: | 类 | 说明 | 影响 | |----|------|------| | `RHIPipelineState` | 管线状态对象 | 无法验证 PSO 创建、配置、绑定 | | `RHIPipelineLayout` | 管线布局 | 无法验证 descriptor layout | | `RHIDescriptorPool` | 描述符池 | Descriptor 管理完全未覆盖 | | `RHIDescriptorSet` | 描述符集 | 无法验证 descriptor 更新 | | `RHIRenderPass` | 渲染通道 | RenderPass API 完全未覆盖 | | `RHIFramebuffer` | 帧缓冲 | Framebuffer API 完全未覆盖 | **修复建议 - 新增 `test_pipeline_state.cpp`**: ```cpp // 文件: tests/RHI/unit/test_pipeline_state.cpp #include "fixtures/RHITestFixture.h" #include "XCEngine/RHI/RHIPipelineState.h" #include "XCEngine/RHI/RHIDevice.h" using namespace XCEngine::RHI; TEST_P(RHITestFixture, PipelineState_Create) { GraphicsPipelineDesc desc = {}; // 配置基本描述符 RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc); ASSERT_NE(pso, nullptr); pso->Shutdown(); delete pso; } TEST_P(RHITestFixture, PipelineState_SetGet_RasterizerState) { GraphicsPipelineDesc desc = {}; RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc); ASSERT_NE(pso, nullptr); RasterizerDesc rasterizer = {}; rasterizer.cullMode = CullMode::Back; pso->SetRasterizerState(rasterizer); EXPECT_EQ(pso->GetRasterizerState().cullMode, CullMode::Back); pso->Shutdown(); delete pso; } TEST_P(RHITestFixture, PipelineState_SetGet_BlendState) { // ... } TEST_P(RHITestFixture, PipelineState_SetGet_DepthStencilState) { // ... } TEST_P(RHITestFixture, PipelineState_Finalize) { GraphicsPipelineDesc desc = {}; RHIPipelineState* pso = GetDevice()->CreatePipelineState(desc); ASSERT_NE(pso, nullptr); bool finalized = pso->Finalize(); EXPECT_TRUE(finalized); EXPECT_TRUE(pso->IsFinalized()); pso->Shutdown(); delete pso; } TEST_P(RHITestFixture, PipelineState_Bind_Unbind) { // ... } ``` **修复建议 - 新增 `test_render_pass.cpp`**: ```cpp // 文件: tests/RHI/unit/test_render_pass.cpp #include "fixtures/RHITestFixture.h" #include "XCEngine/RHI/RHIRenderPass.h" using namespace XCEngine::RHI; TEST_P(RHITestFixture, RenderPass_Create) { AttachmentDesc colorAttachment = {}; colorAttachment.format = Format::R8G8B8A8_UNorm; colorAttachment.loadOp = LoadAction::Clear; colorAttachment.storeOp = StoreAction::Store; RHIRenderPass* renderPass = GetDevice()->CreateRenderPass(1, &colorAttachment, nullptr); ASSERT_NE(renderPass, nullptr); EXPECT_EQ(renderPass->GetColorAttachmentCount(), 1); renderPass->Shutdown(); delete renderPass; } TEST_P(RHITestFixture, RenderPass_BeginEnd) { // 需要先创建 framebuffer // cmdList->BeginRenderPass(renderPass, framebuffer, ...); // cmdList->EndRenderPass(); } ``` **修复建议 - 新增 `test_framebuffer.cpp`**: ```cpp // 文件: tests/RHI/unit/test_framebuffer.cpp #include "fixtures/RHITestFixture.h" #include "XCEngine/RHI/RHIFramebuffer.h" using namespace XCEngine::RHI; TEST_P(RHITestFixture, Framebuffer_Create) { // 先创建 renderPass 和 texture RHIRenderPass* renderPass = ...; RHITexture* texture = ...; RHIResourceView* rtv = GetDevice()->CreateRenderTargetView(texture, {}); RHIFramebuffer* fb = GetDevice()->CreateFramebuffer(renderPass, 1, &rtv, nullptr, 256, 256); ASSERT_NE(fb, nullptr); EXPECT_EQ(fb->GetWidth(), 256); EXPECT_EQ(fb->GetHeight(), 256); EXPECT_TRUE(fb->IsValid()); fb->Shutdown(); delete fb; } ``` **修复建议 - 新增 `test_descriptor.cpp`**: ```cpp // 文件: tests/RHI/unit/test_descriptor.cpp #include "fixtures/RHITestFixture.h" #include "XCEngine/RHI/RHIDescriptorPool.h" #include "XCEngine/RHI/RHIDescriptorSet.h" using namespace XCEngine::RHI; TEST_P(RHITestFixture, DescriptorPool_Create) { DescriptorPoolDesc desc = {}; desc.maxSets = 10; desc.poolSize = 100; RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(desc); ASSERT_NE(pool, nullptr); pool->Shutdown(); } TEST_P(RHITestFixture, DescriptorSet_Allocate_Update) { // 创建 pool RHIDescriptorPool* pool = GetDevice()->CreateDescriptorPool(desc); // 创建 layout DescriptorSetLayoutDesc layoutDesc = {}; DescriptorSetLayoutBinding binding = {}; binding.binding = 0; binding.type = DescriptorType::CBV; binding.count = 1; layoutDesc.bindings = &binding; layoutDesc.bindingCount = 1; RHIDescriptorSet* set = GetDevice()->CreateDescriptorSet(pool, layoutDesc); ASSERT_NE(set, nullptr); EXPECT_EQ(set->GetBindingCount(), 1); set->Shutdown(); pool->Shutdown(); } ``` --- ## 3. 中等问题(P1 - 应该修复) ### 3.1 `tests/RHI/unit/test_command_list.cpp` - 大量测试传递 nullptr **问题描述**: 很多 CommandList 测试只验证调用不崩溃,不验证实际功能: ```cpp // 这些测试传递 nullptr,无法验证真实功能 TEST_P(RHITestFixture, CommandList_ClearRenderTarget) { // ... 创建了 texture 但实际传递 nullptr cmdList->ClearRenderTarget(static_cast(nullptr), color); // 没有验证任何实际行为 } TEST_P(RHITestFixture, CommandList_TransitionBarrier) { // 创建了 texture 但传递 nullptr cmdList->TransitionBarrier(static_cast(nullptr), ...); } TEST_P(RHITestFixture, CommandList_SetVertexBuffer_WithResourceView) { // 直接传递 nullptr RHIResourceView* buffer = nullptr; cmdList->SetVertexBuffers(0, 1, &buffer, nullptr, nullptr); } ``` **缺少的真实测试**: | 测试内容 | 状态 | 建议 | |----------|------|------| | 有资源的 SetVertexBuffer | ❌ | 添加 | | 有资源的 SetIndexBuffer | ❌ | 添加 | | 有资源的 ClearRenderTarget | ❌ | 添加 | | BeginRenderPass/EndRenderPass | ❌ | 添加 | | Dispatch (计算着色器) | ❌ | 添加 | | SetGraphicsDescriptorSets | ❌ | 添加 | | SetComputeDescriptorSets | ❌ | 添加 | **修复建议**: ```cpp // 新增真实资源测试 TEST_P(RHITestFixture, CommandList_SetVertexBuffer_WithRealBuffer) { // 1. 创建 buffer BufferDesc bufDesc = {}; bufDesc.size = 1024; RHIBuffer* buffer = GetDevice()->CreateBuffer(bufDesc); ASSERT_NE(buffer, nullptr); // 2. 创建 cmdList 并设置 RHICommandList* cmdList = GetDevice()->CreateCommandList({}); cmdList->Reset(); RHIResourceView* bufferView = buffer->GetView(); cmdList->SetVertexBuffers(0, 1, &bufferView, nullptr, nullptr); cmdList->Close(); // 3. 清理 cmdList->Shutdown(); buffer->Shutdown(); delete buffer; delete cmdList; } TEST_P(RHITestFixture, CommandList_BeginEndRenderPass) { // 1. 创建 renderPass AttachmentDesc colorDesc = {}; colorDesc.format = Format::R8G8B8A8_UNorm; RHIRenderPass* renderPass = GetDevice()->CreateRenderPass(1, &colorDesc, nullptr); ASSERT_NE(renderPass, nullptr); // 2. 创建 framebuffer TextureDesc texDesc = {}; texDesc.width = 256; texDesc.height = 256; RHITexture* texture = GetDevice()->CreateTexture(texDesc); RHIResourceView* rtv = GetDevice()->CreateRenderTargetView(texture, {}); RHIFramebuffer* fb = GetDevice()->CreateFramebuffer(renderPass, 1, &rtv, nullptr, 256, 256); // 3. 测试 Begin/End RHICommandList* cmdList = GetDevice()->CreateCommandList({}); cmdList->Reset(); Rect renderArea = {0, 0, 256, 256}; ClearValue clearValue = {}; cmdList->BeginRenderPass(renderPass, fb, renderArea, 1, &clearValue); cmdList->EndRenderPass(); cmdList->Close(); // 清理 cmdList->Shutdown(); fb->Shutdown(); delete fb; delete rtv; texture->Shutdown(); delete texture; renderPass->Shutdown(); delete renderPass; } TEST_P(RHITestFixture, CommandList_Dispatch) { // 1. 创建 compute shader ShaderCompileDesc csDesc = {}; RHIShader* computeShader = GetDevice()->CompileShader(csDesc); // ... // 2. 创建并设置 compute pipeline RHIPipelineState* computePSO = GetDevice()->CreatePipelineState(computeDesc); computePSO->SetComputeShader(computeShader); computePSO->Finalize(); // 3. 测试 Dispatch RHICommandList* cmdList = GetDevice()->CreateCommandList({}); cmdList->Reset(); cmdList->SetPipelineState(computePSO); cmdList->Dispatch(8, 8, 1); cmdList->Close(); // 清理 cmdList->Shutdown(); computePSO->Shutdown(); delete computePSO; computeShader->Shutdown(); delete computeShader; } ``` --- ### 3.2 D3D12 后端测试问题 | 文件 | 问题 | 建议 | |------|------|------| | `test_pipeline_state.cpp` | 只测试 struct 默认值 | 添加真实 PSO 创建测试 | | `test_shader.cpp` | 只做字符串比较 | 添加 shader 编译测试 | | `test_root_signature.cpp` | 只测试空签名和 CBV | 添加复杂参数测试 | | `test_command_list.cpp` | 只有 2 个测试 | 补充 Reset/ClearRenderTargetView 等 | **修复建议 - `test_pipeline_state.cpp`**: ```cpp // 当前只有 trivial 测试 TEST_F(D3D12TestFixture, PipelineState_Get_GraphicsPipelineDescDefaults) { D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; // 只验证 struct 默认值 EXPECT_EQ(psoDesc.PrimitiveTopologyType, ...); } // 应该添加 TEST_F(D3D12TestFixture, PipelineState_Create_GraphicsPipeline) { // 1. 创建 root signature D3D12_ROOT_SIGNATURE_DESC rootSigDesc = {}; D3D12RootSignature rootSig; rootSig.Initialize(GetDevice()->GetDevice(), rootSigDesc); // 2. 创建 shader (需要 HLSL 源码或编译好的 bytecode) D3D12Shader* vs = new D3D12Shader(); vs->CompileFromFile(L"shaders/vertex.cso"); // 3. 创建 PSO D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; psoDesc.pRootSignature = rootSig.GetRootSignature(); psoDesc.VS = vs->GetBytecode(); // ... 设置其他字段 ID3D12PipelineState* d3d12PSO = nullptr; HRESULT hr = GetDevice()->GetDevice()->CreateGraphicsPipelineState( &psoDesc, IID_PPV_ARGS(&d3d12PSO)); ASSERT_EQ(hr, S_OK); d3d12PSO->Release(); rootSig.Shutdown(); } ``` --- ### 3.3 OpenGL 后端测试问题 | 文件 | 问题 | 建议 | |------|------|------| | `test_command_list.cpp` | 缺少 SetShader/SetUniform 测试 | 添加 | | `test_shader.cpp` | 无 compute shader 测试 | 添加 GL_COMPUTE_SHADER | | 无 compute 相关测试 | 缺少 Dispatch 测试 | 添加 | **修复建议**: ```cpp // 新增 test_compute.cpp TEST_F(OpenGLTestFixture, ComputeShader_Compile) { const char* computeSrc = R"( #version 460 layout(local_size_x = 1, local_size_y = 1) in; void main() { // compute shader } )"; OpenGLShader computeShader; bool compiled = computeShader.CompileCompute(computeSrc); EXPECT_TRUE(compiled); } TEST_F(OpenGLTestFixture, CommandList_Dispatch) { // 编译 compute shader OpenGLShader computeShader; computeShader.CompileCompute(computeSrc); // 创建 pipeline state OpenGLPipelineState pipeline; pipeline.SetComputeShader(&computeShader); pipeline.Apply(); // 测试 Dispatch OpenGLCommandList cmdList; cmdList.Reset(); cmdList.SetPipelineState(&pipeline); cmdList.Dispatch(8, 8, 1); cmdList.Close(); } ``` --- ## 4. 测试覆盖度矩阵 ### 4.1 RHI 抽象层覆盖度 | RHI 抽象接口 | 覆盖状态 | 备注 | |--------------|----------|------| | Device 创建/初始化 | ✅ 已覆盖 | | | Buffer 创建/映射 | ✅ 已覆盖 | | | Texture 创建 | ✅ 已覆盖 | | | SwapChain | ✅ 已覆盖 | | | CommandList 基础 | ⚠️ 太弱 | 大部分传递 nullptr | | CommandQueue | ✅ 已覆盖 | | | Fence | ✅ 已覆盖 | | | Sampler | ✅ 已覆盖 | | | Shader 编译 | ✅ 已覆盖 | 7个有效测试,使用内嵌源码 | | **PipelineState** | ✅ 已覆盖 | 10个测试,已完成 | | **PipelineLayout** | ❌ 无测试 | **必须添加** | | **DescriptorPool** | ✅ 已覆盖 | 8个测试,已完成 | | **DescriptorSet** | ⚠️ 部分覆盖 | OpenGL 需要 GL context | | **RenderPass** | ✅ 已覆盖 | 10个测试,已完成 | | **Framebuffer** | ✅ 已覆盖 | 8个测试,已完成 | | **Compute/Dispatch** | ✅ 已覆盖 | 8个测试,已完成 | ### 4.2 D3D12 后端覆盖度 | D3D12 特定功能 | 覆盖状态 | 备注 | |----------------|----------|------| | 设备特性检测 | ✅ 已覆盖 | | | Descriptor Heap | ✅ 已覆盖 | | | Command Allocator | ✅ 已覆盖 | | | Fence Timeline | ✅ 已覆盖 | | | RootSignature | ⚠️ 弱 | 只测试空签名和 CBV | | PipelineState | ⚠️ 弱 | 只测试 struct 默认值 | | Shader | ⚠️ 弱 | 只做字符串比较 | | SwapChain | ✅ 已覆盖 | | | Views (RTV/DSV) | ✅ 已覆盖 | | ### 4.3 OpenGL 后端覆盖度 | OpenGL 特定功能 | 覆盖状态 | 备注 | |----------------|----------|------| | Buffer (VBO/IBO/UBO) | ✅ 已覆盖 | | | Texture (2D/Cube) | ✅ 已覆盖 | | | VertexArray | ✅ 已覆盖 | | | Shader 编译 | ✅ 已覆盖 | | | PipelineState | ✅ 已覆盖 | | | Sampler | ✅ 已覆盖 | | | Fence | ✅ 已覆盖 | | | SwapChain | ✅ 已覆盖 | | | **Compute Shader** | ❌ 无测试 | **必须添加** | | **Dispatch** | ❌ 无测试 | **必须添加** | | Memory Barrier | ❌ 无测试 | 可选 | --- ## 5. 重构优先级总结 ### P0 - 必须修复(影响功能验证) | 优先级 | 问题 | 工作量 | 影响 | 状态 | |--------|------|--------|------|------| | 1 | Shader 测试重构 | 中 | 9个测试无效 | ✅ 已完成 | | 2 | 添加 PipelineState 测试 | 大 | RHI 核心组件无测试 | ✅ 已完成 | | 3 | 添加 RenderPass 测试 | 中 | 重要 API 未覆盖 | ✅ 已完成 | | 4 | 添加 Framebuffer 测试 | 中 | 重要 API 未覆盖 | ✅ 已完成 | ### P1 - 应该修复(提高覆盖率) | 优先级 | 问题 | 工作量 | 影响 | 状态 | |--------|------|--------|------|------| | 5 | 添加 DescriptorPool 测试 | 中 | 已实现未测试 | ✅ 已完成 (DescriptorPool) | | 5b | DescriptorSet 测试 | 中 | OpenGL 需要 GL context,暂跳过 | ⚠️ 待完成 | | 6 | CommandList 测试增强 | 大 | 大部分传递 nullptr | ⏳ 待完成 | | 7 | 添加 Compute/Dispatch 测试 | 中 | 重要功能缺失 | ✅ 已完成 | | 8 | D3D12 PSO/shader 测试增强 | 小 | 当前测试 trivial | ⏳ 待完成 | ### P2 - 可以修复(完善细节) | 优先级 | 问题 | 工作量 | 影响 | |--------|------|--------|------| | 9 | OpenGL CommandList SetShader 测试 | 小 | 缺失测试 | | 10 | 复杂 RootSignature 参数测试 | 小 | 当前只测试 CBV | | 11 | OpenGL Compute Shader 测试 | 小 | 缺失测试 | --- ## 6. 新增测试文件清单 | 文件路径 | 测试内容 | 优先级 | 状态 | |----------|----------|--------|------| | `tests/RHI/unit/test_pipeline_state.cpp` | PipelineState 创建/配置/绑定 | P0 | ✅ 已完成 | | `tests/RHI/unit/test_render_pass.cpp` | RenderPass 创建/Begin/End | P0 | ✅ 已完成 | | `tests/RHI/unit/test_framebuffer.cpp` | Framebuffer 创建/绑定 | P0 | ✅ 已完成 | | `tests/RHI/unit/test_descriptor.cpp` | DescriptorPool 创建/更新 | P1 | ✅ DescriptorPool完成, Set待完成 | | `tests/RHI/unit/test_compute.cpp` | Compute shader/Dispatch | P1 | ✅ 已完成 | | `tests/RHI/unit/test_pipeline_layout.cpp` | PipelineLayout 创建 | P2 | ⏳ 待完成 | --- ## 7. 测试质量改进建议 ### 7.1 测试命名规范 遵循 `Component_Category_SubBehavior` 格式: ``` Good: - Buffer_Create_DefaultHeap - CommandList_SetViewport_ValidRect - Shader_Compile_ValidSource Bad: - Test1 - BufferTest - test_buffer ``` ### 7.2 测试结构规范 每个测试应包含: ```cpp TEST_P(RHITestFixture, CommandList_SetVertexBuffer_WithRealBuffer) { // 1. Arrange - 准备测试数据 BufferDesc bufDesc = {}; bufDesc.size = 1024; RHIBuffer* buffer = GetDevice()->CreateBuffer(bufDesc); ASSERT_NE(buffer, nullptr); // 使用 ASSERT 防止空指针解引用 // 2. Act - 执行被测操作 RHICommandList* cmdList = GetDevice()->CreateCommandList({}); cmdList->Reset(); RHIResourceView* view = buffer->GetView(); cmdList->SetVertexBuffers(0, 1, &view, nullptr, nullptr); cmdList->Close(); // 3. Assert - 验证结果 // 注意:有些测试难以直接验证结果,可以通过不崩溃来间接验证 // 4. Cleanup - 清理资源 cmdList->Shutdown(); delete cmdList; buffer->Shutdown(); delete buffer; } ``` ### 7.3 避免的问题 ```cpp // 问题1: 测试逻辑完全相同 TEST_P(RHITestFixture, Shader_Test1) { shader = nullptr; EXPECT_EQ(shader, nullptr); } TEST_P(RHITestFixture, Shader_Test2) { shader = nullptr; EXPECT_EQ(shader, nullptr); } // 相同! // 问题2: 传递 nullptr 不验证功能 TEST_P(RHITestFixture, CommandList_Test) { cmdList->ClearRenderTarget(nullptr, color); // 无意义 } // 问题3: 不清理资源 TEST_P(RHITestFixture, Buffer_Test) { RHIBuffer* buffer = device->CreateBuffer(desc); // 忘记 buffer->Shutdown() 和 delete buffer } // 问题4: 缺少 ASSERT TEST_P(RHITestFixture, Buffer_Test) { RHIBuffer* buffer = device->CreateBuffer(desc); buffer->SetData(...); // 如果 buffer 是 nullptr 则崩溃 // 应该先 ASSERT_NE(buffer, nullptr); } ``` --- ## 8. 附录:测试执行命令 ```bash # 增量构建 RHI 测试 cmake --build . --target rhi_unit_tests --config Debug cmake --build . --target rhi_d3d12_tests --config Debug cmake --build . --target rhi_opengl_tests --config Debug # 运行 RHI 抽象层测试 (同时验证 D3D12 和 OpenGL) ctest -R "^D3D12/|^OpenGL/" -C Debug --output-on-failure # 运行 D3D12 后端专用测试 ctest -R "D3D12TestFixture|SwapChainTestFixture" -C Debug --output-on-failure # 运行 OpenGL 后端专用测试 ctest -R "OpenGLTestFixture" -C Debug --output-on-failure # 运行所有 RHI 测试 ctest -R "D3D12|OpenGL|RHITestFixture" -C Debug --output-on-failure ``` --- **文档版本**: 1.4 **最后更新**: 2026-03-25 **作者**: XCEngine Team ## 更新日志 ### v1.4 (2026-03-25) - P1-7: Compute/Dispatch 测试 ✅ 已完成 - 新增 `test_compute.cpp`,8个测试 - 测试通过:D3D12 8 + OpenGL 8 = 16 tests - 修复 shader type bugs: - `D3D12Shader::Compile` 不设置 `m_type` - `OpenGLShader::Compile(const void*,...)` 硬编码 Fragment - `OpenGLShader::CompileCompute` 不设置 `m_type` - 修复 `D3D12CommandList::SetPipelineState` 对 Compute PSO 用错 handle - 测试结果:D3D12 116测试 + OpenGL 116测试 = 232测试全部通过 - 集成测试:8/8 全部通过 ### v1.3 (2026-03-25) - P1-5: DescriptorPool 测试 ✅ 已完成 - 新增 `test_descriptor.cpp`,8个 DescriptorPool 测试 - 测试通过:D3D12 8 + OpenGL 8 = 16 tests - DescriptorSet 测试暂跳过(OpenGL 需要 GL context) - 测试结果:D3D12 108测试 + OpenGL 108测试 = 216测试全部通过 - 集成测试:8/8 全部通过 ### v1.2 (2026-03-25) - P0-3: RenderPass 测试 ✅ 已完成 - 新增 `test_render_pass.cpp`,10个测试 - 添加 `CreateRenderPass/CreateFramebuffer` 到 `RHIDevice` 接口 - 实现 D3D12 和 OpenGL 后端 - 修复 D3D12 depth stencil 资源创建(自动设置 `D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL`) - 修复 D3D12 RTV/DSV 空指针检查 - P0-4: Framebuffer 测试 ✅ 已完成 - 新增 `test_framebuffer.cpp`,8个测试 - 修复 `D3D12RenderPass` 的 `StoreAndResolve` 映射问题 - 测试结果:D3D12 100测试 + OpenGL 100测试 = 200测试全部通过 - 集成测试:8/8 全部通过 ### v1.1 (2026-03-25) - P0-1: Shader 测试重构 ✅ 已完成 - 添加 `ShaderLanguage` 枚举 - 扩展 `ShaderCompileDesc` 支持内嵌源码 - 9个相同测试 → 7个有效测试 - P0-2: PipelineState 测试 ✅ 已完成 - 新增 `test_pipeline_state.cpp` - 修复 PSO 验证接口:`IsFinalized/Finalize` → `IsValid/EnsureValid` - 10个测试覆盖创建、配置、状态查询、生命周期 ### v1.0 (2026-03-25) - 初始版本