如何在测试套件中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时需分别实现;不能直接Mock
SolidColorBrush具体类,因为它是密封类无法被继承。
解决方案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
相关产品推荐
相关产品推荐

