Я пытаюсь проверить ViewComponent, чтобы увидеть, возвращает ли он правильное количество элементов RSS. ResultList содержит ссылку на данные модели, и с помощью быстрого просмотра я могу видеть содержимое IEnumerable.
Однако при вызове Count, First или даже ToList возникает исключение NullReferenceException! ResultList не является нулевым.
Что происходит за сценой?
var result = await model.InvokeAsync(listLength);
var resultList = (result as ViewViewComponentResult).ViewData.Model as IEnumerable<LatestArticlesViewComponent.RssItem>;
Assert.Equal(listLength, resultList.Count());
RssItem - очень простой класс
public class RssItem
{
public string Uri { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
}
РЕДАКТИРОВАТЬ: вот полный тест
private LatestArticlesConfig _config;
private Mock<ISyndicationFeedService> _rssMock;
private const string _validUri = "valid";
private const string _invalidUri = "invalid";
private LatestArticlesViewComponent SetupModel()
{
_config = new LatestArticlesConfig();
_rssMock = new Mock<ISyndicationFeedService>();
var rssItems = new List<SyndicationItem>();
for (int i=0; i<10; i++)
{
rssItems.Add(new SyndicationItem($"title{i}", new string(i.ToString()[0], 500), new Uri("http://uri.com")));
}
_rssMock.Setup(x => x.Load(_validUri)).Returns(new SyndicationFeed(rssItems));
_rssMock.Setup(x => x.Load(_invalidUri)).Callback(() => throw new XmlException());
return new LatestArticlesViewComponent(_config, _rssMock.Object);
}
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(5)]
public async Task InvokeAsync_ListLength_ListWithSpecifiedLength(int listLength)
{
var model = SetupModel();
_config.ArticlesRss = _validUri;
var result = await model.InvokeAsync(listLength);
var resultList = GetResultModel(result);
Assert.Equal(listLength, resultList.Count());
}
private IEnumerable<LatestArticlesViewComponent.RssItem> GetResultModel(IViewComponentResult result)
{
return (result as ViewViewComponentResult).ViewData.Model as IEnumerable<LatestArticlesViewComponent.RssItem>;
}
и ViewComponent, который я тестирую
public class LatestArticlesViewComponent : ViewComponent
{
private readonly LatestArticlesConfig _config;
private readonly ISyndicationFeedService _rss;
public LatestArticlesViewComponent(LatestArticlesConfig config, ISyndicationFeedService rss)
{
_rss = rss ?? throw new ArgumentNullException(nameof(rss));
_config = config ?? throw new ArgumentNullException(nameof(config));
}
public async Task<IViewComponentResult> InvokeAsync(int listLength = 4, int maxTextLength = 128)
{
if (listLength < 0)
throw new ArgumentOutOfRangeException(nameof(listLength), "ListLength cannot be negative.");
if (maxTextLength < 0)
throw new ArgumentOutOfRangeException(nameof(maxTextLength), "MaxTextLength cannot be negative.");
// System.Net.ServicePointManager.ServerCertificateValidationCallback = (s, cert, chain, ssl) => true;
try
{
var feed = await Task.Run(() => _rss.Load(_config.ArticlesRss));
var items = feed.Items.Take(listLength).ToList().Select(x => new RssItem()
{
Uri = x.Links[0].Uri.ToString(),
Title = x.Title.Text,
Summary = TrimText(HtmlToPlainText(x.Summary.Text), maxTextLength)
});
return View(items);
}
catch {
return Content(string.Empty);
}
}
private string TrimText(string title, int length)
{
var result = title;
if (title.Length > length)
{
result = title.Substring(0, length).Trim();
result += "…";
}
return result;
}
private string HtmlToPlainText(string html) => new Regex("<[^>]*>", RegexOptions.Multiline).Replace(html, string.Empty);
public class RssItem
{
public string Uri { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
}
}