如何使用 Rust for Windows API 创建模拟 Web::Synmination::SynminationFeed 进行单元测试

问题描述 投票:0回答:1

我从 Microsoft 网站上记录的 Rust for Windows RSS reader 示例开始。它按预期工作,但相当简单。我想扩展这个示例,将其变成有用的东西,并创建一个包含单元测试的示例项目。

我的应用程序代码确实按预期工作。由于网络问题是常见错误,因此我构建了 main 结构,以便检索提要的外部调用位于一个函数中,而解析提要(如果返回)的代码位于另一个函数中。

fn check_syndication(client: &SyndicationClient) -> Result<SyndicationFeed> {
    let uri = Uri::CreateUri(h!("https://rpilocator.com/feed"))?;
    client.RetrieveFeedAsync(&uri)?.get()
}

fn parse_syndication(syndication_feed: SyndicationFeed) -> Vec<String> {
    let feed_items: IVector<SyndicationItem> = syndication_feed.Items().unwrap();

    feed_items
        .into_iter()
        .map(|item| item.Title().unwrap().Text().unwrap().to_string())
        .collect::<Vec<String>>()
}

这个想法是创建一个模拟 SyndicateFeed 对象,然后将其传递到我的

parse_syndication()
函数中,如下所示:

#[test]
fn verify_parse_syndication() {
   let mock_uri = Uri::CreateUri(h!("https://mock_url.com")).unwrap();
   let mock_feed = SyndicationFeed::CreateSyndicationFeed(
      &HSTRING::from("Mock Title"),
      &HSTRING::from("Mock Subtitle"),
      &mock_uri,
   ).unwrap();
   
   let output = parse_syndication(mock_feed);
   assert_eq!(output.len(), 1);
}

虽然此测试确实编译并创建了一个空的

SyndicationFeed
,但我无法弄清楚如何填充它,以便
SyndicationFeed.Items
包含一个模拟的项目列表。

IVector<SyndicationItem>

GitHub 上的完整源代码

SynminationFeed 文档 并不表示存在任何类型的

add()
insert()
功能。
CreateSyndicationFeed()
函数似乎没有提供用数据初始化
SyndicationFeed
的方法。在我对 GitHub、SO 或 Google 的搜索中,我还没有找到其他创建示例。我还在 API 中搜索了工厂模式以及其他类似类型对象的创建。

我确实尝试了一种不同的方法,在 xml 文件中创建了一个模拟 RSS 提要。然后,我创建了一个指向本地资源的 URI 对象,并将其作为

RetrieveFeedAsync()
调用的输入提供。不幸的是我也无法让它发挥作用。混合 URI 语法中的正斜杠和路径缓冲区中的反斜杠存在多个问题。即使使用本地资源的硬编码字符串也无法打开该文件。我最终放弃了这种方法。

unit-testing rust mocking windows-rs
1个回答
0
投票

正如 IInspectable 建议的那样, 我能够使用字符串生成模拟 XmlDocument 并调用 SyndicateFeed::LoadFromXml 来获取我可以测试的预期 SyndicateFeed 输出。

mod tests {
    use super::*;
    use windows::Data::Xml::Dom::XmlLoadSettings;
    pub struct XmlDoc {
        mock_xml: XmlDocument,
    }

    impl Default for XmlDoc {
        fn default() -> Self {
            let xml = String::from(
                "\
                <?xml version=\"1.0\" encoding=\"UTF-8\" ?><rss version=\"2.0\">\
                    <channel>\
                        <title>Mock Channel Title</title>\
                        <link>https://mockchannellink.com</link>\
                        <description>Mock Channel Description</description>\
                        <lastbuilddate>Fri, 08 Dec 2023 01:00:00 GMT</lastbuilddate>\
                        <item>\
                            <title>Mock Item Title</title>\
                            <description>Mock Item Description.</description>\
                            <link>https://mockitemlink.com</link>\
                            <guid ispermalink=\"false\">846c1690-b4ad-479a-95e3-2ca5ed4dfdbd</guid>\
                            <pubdate>Fri, 08 Dec 2023 01:00:00 GMT</pubdate>\
                        </item>\
                    </channel>\
                </rss>\
                ",
            );

            let xml_opts = XmlLoadSettings::new().expect("Opts creation failed");
            xml_opts
                .SetValidateOnParse(true)
                .expect("Set validate option failed");

            let mock_xml: XmlDocument = XmlDocument::new().expect("New XmlDoc::new failed");
            match mock_xml.LoadXmlWithSettings(&HSTRING::from(xml), &xml_opts) {
                Ok(doc) => doc,
                Err(e) => {
                    println!("LoadXml failed: {}", e.code());
                }
            };
            Self { mock_xml }
        }
    }

    #[test]
    fn verify_parse_syndication() {
        let xml_doc = XmlDoc::default().mock_xml;

        let mock_feed = SyndicationFeed::new().expect("New SyndicationFeed failed");
        mock_feed
            .LoadFromXml(&xml_doc)
            .expect("Load from xml failed");
        let output = parse_syndication(mock_feed);
        assert_eq!(output.len(), 1);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.