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

如何在测试套件中Mock Windows APP SDK的SolidColorBrush等UI元素?

如何Mock WinUI的SolidColorBrush及其他UI元素?

问题根源

直接创建SolidColorBrush抛出winrt::hresult_wrong_thread,是因为WinUI的XAML元素必须在UI线程(单线程公寓/STA线程)上下文创建,测试环境默认未初始化该线程环境;而尝试Mock时出错,是因为WinRT的具体控件类是密封类,无法直接继承或通过winrt::implementsMock具体类,必须Mock其对应的接口。


解决方案1:初始化UI线程环境创建真实对象

如果测试仅需要使用真实的SolidColorBrush,无需Mock,可在测试中初始化STA线程环境:

#include <winrt/Microsoft.UI.Xaml.h>
#include <winrt/Microsoft.UI.Xaml.Media.h>
#include <gtest/gtest.h>

TEST(SolidColorBrushTest, CreateOnUIThread)
{
    // 初始化单线程公寓(UI线程环境)
    winrt::init_apartment(winrt::apartment_type::single_threaded);
    
    constexpr winrt::Windows::UI::Color color(100, 101, 102, 103);
    const auto brush = winrt::Microsoft::UI::Xaml::Media::SolidColorBrush(color);
    
    // 执行测试逻辑
    ASSERT_EQ(brush.Color().R, 100);
}

解决方案2:正确Mock WinRT接口

WinRT控件基于COM接口实现,需Mock其对应的接口而非具体类。以SolidColorBrush为例,它实现了ISolidColorBrush接口,Mock代码如下:

#include <gmock/gmock.h>
#include <winrt/Microsoft.UI.Xaml.Media.h>

// Mock ISolidColorBrush接口
struct MockSolidColorBrush : winrt::implements<MockSolidColorBrush, winrt::Microsoft::UI::Xaml::Media::ISolidColorBrush>
{
    // Mock Color属性的getter和setter
    MOCK_METHOD(winrt::Windows::UI::Color, Color, (), (const noexcept));
    MOCK_METHOD(void, Color, (winrt::Windows::UI::Color), (noexcept));
    
    // 需Mock接口的所有方法(如IBrush的成员)
    MOCK_METHOD(double, Opacity, (), (const noexcept));
    MOCK_METHOD(void, Opacity, (double), (noexcept));
    MOCK_METHOD(winrt::Microsoft::UI::Xaml::Media::Brush, Clone, (), (noexcept));
    MOCK_METHOD(winrt::Microsoft::UI::Xaml::Media::Brush, CloneCurrentValue, (), (noexcept));
};

// 测试使用Mock对象
TEST(SolidColorBrushMockTest, VerifyColorGetter)
{
    MockSolidColorBrush mockBrush;
    winrt::Microsoft::UI::Xaml::Media::ISolidColorBrush brush = mockBrush;

    EXPECT_CALL(mockBrush, Color())
        .WillOnce(testing::Return(winrt::Windows::UI::Color{100,101,102,103}));

    auto color = brush.Color();
    ASSERT_EQ(color.G, 101);
}

注意:WinRT接口的属性对应成对的get/set方法,Mock时需分别实现;不能直接MockSolidColorBrush具体类,因为它是密封类无法被继承。


解决方案3:依赖自定义抽象(推荐)

在业务代码中封装自定义抽象接口,解耦与WinRT具体类型的依赖,测试时Mock自定义接口即可完全避开UI线程和WinRT Mock问题:

#include <gmock/gmock.h>
#include <winrt/Microsoft.UI.Xaml.Media.h>
#include <memory>

// 自定义抽象接口
struct IBrushProvider
{
    virtual winrt::Microsoft::UI::Xaml::Media::Brush GetSolidColorBrush(winrt::Windows::UI::Color color) = 0;
    virtual ~IBrushProvider() = default;
};

// 生产环境实现
class DefaultBrushProvider : public IBrushProvider
{
public:
    winrt::Microsoft::UI::Xaml::Media::Brush GetSolidColorBrush(winrt::Windows::UI::Color color) override
    {
        return winrt::Microsoft::UI::Xaml::Media::SolidColorBrush(color);
    }
};

// 业务代码依赖抽象
class ThemeService
{
public:
    ThemeService(std::unique_ptr<IBrushProvider> provider) : m_provider(std::move(provider)) {}

    winrt::Microsoft::UI::Xaml::Media::Brush GetPrimaryBrush()
    {
        return m_provider->GetSolidColorBrush({255, 0, 0, 255});
    }

private:
    std::unique_ptr<IBrushProvider> m_provider;
};

// 测试Mock自定义接口
struct MockBrushProvider : public IBrushProvider
{
    MOCK_METHOD(winrt::Microsoft::UI::Xaml::Media::Brush, GetSolidColorBrush, (winrt::Windows::UI::Color), (override));
};

TEST(ThemeServiceTest, GetPrimaryBrush)
{
    auto mockProvider = std::make_unique<MockBrushProvider>();
    MockSolidColorBrush mockBrush;
    winrt::Microsoft::UI::Xaml::Media::Brush testBrush = mockBrush;

    EXPECT_CALL(*mockProvider, GetSolidColorBrush(testing::_))
        .WillOnce(testing::Return(testBrush));

    ThemeService service(std::move(mockProvider));
    auto brush = service.GetPrimaryBrush();
    ASSERT_TRUE(brush);
}

内容的提问来源于stack exchange,提问作者UnclePooh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 20:15:29