如何使用GoogleTest对Renderer API进行单元测试?
问题描述
我正在编写的库中包含如下Renderer API:
class EXPORT Renderer { public: Renderer(const Renderer &) = delete; Renderer &operator=(const Renderer &) = delete; virtual ~Renderer(); protected: Renderer() = default; public: [[nodiscard]] static std::unique_ptr<Renderer> create(const RendererDescriptor &descriptor); [[nodiscard]] virtual std::unique_ptr<SwapChain> createSwapChain(const SwapChainDescriptor &descriptor, const Window &window) = 0; [[nodiscard]] virtual std::unique_ptr<Buffer> createVertexBuffer(const BufferDescriptor &descriptor, const VertexFormat &format) = 0; [[nodiscard]] virtual std::unique_ptr<Buffer> createIndexBuffer(const BufferDescriptor &descriptor, Format format) = 0; [[nodiscard]] virtual std::unique_ptr<Shader> createShaderFromString(const ShaderDescriptor &descriptor, std::string_view source) = 0; [[nodiscard]] virtual std::unique_ptr<PipelineState> createPipelineState(const PipelineStateDescriptor &descriptor) = 0; [[nodiscard]] virtual std::unique_ptr<CommandList> createCommandList(const CommandListDescriptor &descriptor) = 0; [[nodiscard]] virtual std::unique_ptr<Texture> createTexture(const TextureDescriptor &descriptor) = 0; [[nodiscard]] virtual std::unique_ptr<RenderTarget> createRenderTarget(const RenderTargetDescriptor &descriptor) = 0; [[nodiscard]] virtual std::unique_ptr<RenderPass> createRenderPass(const RenderPassDescriptor &descriptor) = 0; };
该Renderer API在另一库中实现了OpenGL后端,示例如下:
class GLRenderer final : public Renderer { public: explicit GLRenderer(const RendererDescriptor &descriptor); std::unique_ptr<SwapChain> createSwapChain(const SwapChainDescriptor &descriptor, const Window &window) override; std::unique_ptr<Buffer> createVertexBuffer(const BufferDescriptor &descriptor, const VertexFormat &format) override; std::unique_ptr<Buffer> createIndexBuffer(const BufferDescriptor &descriptor, Format format) override; std::unique_ptr<Shader> createShaderFromString(const ShaderDescriptor &descriptor, std::string_view source) override; std::unique_ptr<PipelineState> createPipelineState(const PipelineStateDescriptor &descriptor) override; std::unique_ptr<CommandList> createCommandList(const CommandListDescriptor &descriptor) override; std::unique_ptr<Texture> createTexture(const TextureDescriptor &descriptor) override; std::unique_ptr<RenderTarget> createRenderTarget(const RenderTargetDescriptor &descriptor) override; std::unique_ptr<RenderPass> createRenderPass(const RenderPassDescriptor &descriptor) override; private: // private members };
Renderer::create工厂方法会加载此OpenGL后端库并分配GLRenderer实例后返回。请问应如何使用GoogleTest对该API进行单元测试?
测试方案
针对这个Renderer API的单元测试,可以围绕实例创建有效性、资源创建逻辑、边界参数处理三个核心方向展开,利用GoogleTest的断言机制验证行为:
1. 基础实例创建测试
先验证Renderer工厂方法的核心逻辑:正常配置能返回有效实例,无效配置返回空。
TEST(RendererTest, CreateInstanceWithValidDescriptor) { RendererDescriptor desc; desc.api = RenderAPI::OpenGL; desc.debug = true; // 开启调试模式 auto renderer = Renderer::create(desc); ASSERT_NE(renderer, nullptr); // 验证实例非空 } TEST(RendererTest, CreateInstanceWithInvalidAPI) { RendererDescriptor invalid_desc; invalid_desc.api = RenderAPI::Unknown; // 传入不支持的API类型 auto renderer = Renderer::create(invalid_desc); ASSERT_EQ(renderer, nullptr); // 验证无效配置返回空 }
2. 各类资源创建测试
针对每个createXXX方法,覆盖正常创建、边界参数、错误参数三种场景:
顶点缓冲区创建测试
TEST(RendererTest, CreateVertexBufferWithValidParams) { auto renderer = Renderer::create(GetValidRendererDescriptor()); ASSERT_NE(renderer, nullptr); BufferDescriptor buffer_desc; buffer_desc.size = 1024; // 1KB缓冲区 buffer_desc.usage = BufferUsage::Vertex; buffer_desc.memory_type = MemoryType::HostVisible; VertexFormat vertex_format; vertex_format.attributes = { {AttributeType::Position, Format::Float3}, {AttributeType::UV, Format::Float2} }; auto vertex_buffer = renderer->createVertexBuffer(buffer_desc, vertex_format); ASSERT_NE(vertex_buffer, nullptr); // 若Buffer类有查询接口,可进一步验证属性 EXPECT_EQ(vertex_buffer->getSize(), 1024); } TEST(RendererTest, CreateVertexBufferWithZeroSize) { auto renderer = Renderer::create(GetValidRendererDescriptor()); ASSERT_NE(renderer, nullptr); BufferDescriptor buffer_desc; buffer_desc.size = 0; // 无效的缓冲区大小 buffer_desc.usage = BufferUsage::Vertex; VertexFormat vertex_format; // 配置合法的顶点格式 auto vertex_buffer = renderer->createVertexBuffer(buffer_desc, vertex_format); ASSERT_EQ(vertex_buffer, nullptr); // 验证非法参数返回空 }
着色器创建测试
TEST(RendererTest, CreateShaderWithValidSource) { auto renderer = Renderer::create(GetValidRendererDescriptor()); ASSERT_NE(renderer, nullptr); ShaderDescriptor shader_desc; shader_desc.type = ShaderType::Vertex; shader_desc.stage = ShaderStage::Vertex; // 合法的GLSL顶点着色器源码 std::string_view source = R"( #version 450 core layout(location = 0) in vec3 aPos; void main() { gl_Position = vec4(aPos, 1.0); } )"; auto shader = renderer->createShaderFromString(shader_desc, source); ASSERT_NE(shader, nullptr); } TEST(RendererTest, CreateShaderWithInvalidSource) { auto renderer = Renderer::create(GetValidRendererDescriptor()); ASSERT_NE(renderer, nullptr); ShaderDescriptor shader_desc; shader_desc.type = ShaderType::Vertex; // 存在语法错误的源码 std::string_view bad_source = R"( #version 450 core layout(location = 0) in vec3 aPos; void main() { gl_Position = vec4(aPos); // 缺少第四个分量参数 } )"; auto shader = renderer->createShaderFromString(shader_desc, bad_source); ASSERT_EQ(shader, nullptr); // 验证错误源码返回空 }
3. 窗口依赖资源测试(如SwapChain)
SwapChain依赖Window实例,测试时可使用离线窗口(无显示)或模拟窗口对象:
TEST(RendererTest, CreateSwapChainWithValidWindow) { auto renderer = Renderer::create(GetValidRendererDescriptor()); ASSERT_NE(renderer, nullptr); // 创建无显示的测试窗口(例如GLFW的offscreen模式) Window test_window; test_window.create(800, 600, "Test Window", WindowMode::Offscreen); ASSERT_TRUE(test_window.isValid()); SwapChainDescriptor sc_desc; sc_desc.width = 800; sc_desc.height = 600; sc_desc.format = Format::RGBA8Unorm; auto swap_chain = renderer->createSwapChain(sc_desc, test_window); ASSERT_NE(swap_chain, nullptr); EXPECT_EQ(swap_chain->getWidth(), 800); }
4. 测试框架优化配置
- 使用测试夹具:通过
SetUp()和TearDown()方法复用Renderer实例创建逻辑,减少重复代码:class RendererTestFixture : public ::testing::Test { protected: void SetUp() override { renderer = Renderer::create(GetValidRendererDescriptor()); } void TearDown() override { renderer.reset(); } std::unique_ptr<Renderer> renderer; }; // 基于夹具的测试案例 TEST_F(RendererTestFixture, CreateCommandListSuccess) { ASSERT_NE(renderer, nullptr); CommandListDescriptor cmd_desc; auto cmd_list = renderer->createCommandList(cmd_desc); ASSERT_NE(cmd_list, nullptr); } - 链接依赖:测试项目需链接GoogleTest库、Renderer库以及OpenGL后端库,确保编译时能找到所有符号。
- 资源清理:每个测试案例结束后主动释放GPU资源,避免状态污染或内存泄漏。
内容的提问来源于stack exchange,提问作者RafalMaziejuk
相关产品推荐
相关产品推荐

