我从 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>
SynminationFeed 文档 并不表示存在任何类型的
add()
或 insert()
功能。 CreateSyndicationFeed()
函数似乎没有提供用数据初始化SyndicationFeed
的方法。在我对 GitHub、SO 或 Google 的搜索中,我还没有找到其他创建示例。我还在 API 中搜索了工厂模式以及其他类似类型对象的创建。
我确实尝试了一种不同的方法,在 xml 文件中创建了一个模拟 RSS 提要。然后,我创建了一个指向本地资源的 URI 对象,并将其作为
RetrieveFeedAsync()
调用的输入提供。不幸的是我也无法让它发挥作用。混合 URI 语法中的正斜杠和路径缓冲区中的反斜杠存在多个问题。即使使用本地资源的硬编码字符串也无法打开该文件。我最终放弃了这种方法。
正如 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);
}
}