我不确定这是否是Moq问题,或者我做了一些盲目明显的事情,而且我已经看了太久了。
我通过以下声明获得了一些非常奇怪的结果:
var orderedFiles = files
.Select(p => {
var post = _serializer.Deserialize<BlogPostModel>(_fs.File.ReadAllText(p));
post.FileDate = GetFileNameDate(p);
post.FilePath = p;
return post;
})
.OrderByDescending(x => x.FileDate);
当我枚举这个时,(通过使用orderedFiles.ToArray()或.ToList())我得到了原始“files”数组中的LAST元素,该数组返回给枚举中的所有元素。因此,对于下面的测试,我得到预计的file5值,5次。
当我在Select()方法调用中放置断点时,每次迭代都返回正确的值。在我枚举后,值都是相同的 - 截图如下:
上图:从Select()中正确返回投影值 - 每次迭代都会返回一个完全不同的对象。
上图:枚举值都等于原始GetFiles()调用的最后一个元素,您可以通过Locals窗口中的两个展开元素看到。
这是我的测试(当调用GetService()时,模拟被插入到服务中,并且在nunit SetUp方法中将许多全局设置放在一起):
[Test]
public void GetBlogPosts_PicksUpFilesInReverseFileNameDateOrder() {
// Arrange
var file1 = Path.Combine(blogPathContent, "2013-12-28-04-31-41-this-is-the-blog-title-1.json"); // 2
var file2 = Path.Combine(blogPathContent, "2013-10-09-01-54-43-this-is-the-blog-title-2.json"); // 3
var file3 = Path.Combine(blogPathContent, "2014-01-12-18-52-32-this-is-the-blog-title-3.json"); // 1
var file4 = Path.Combine(blogPathContent, "2012-12-20-06-18-23-this-is-the-blog-title-5.json"); // 5
var file5 = Path.Combine(blogPathContent, "2013-06-04-12-28-56-this-is-the-blog-title-4.json"); // 4
mockSerializer
.Setup(x => x.Deserialize<BlogPostModel>(It.IsAny<string>()))
.Returns(new BlogPostModel());
mockDirectory
.Setup(x => x.GetFiles(It.Is<string>(s => s == blogPathContent),
It.Is<string>(s => s == string.Concat("*", blogFilesExt))))
.Returns(new[] {file1, file2, file3, file4, file5});
service = GetService();
// Act
var actualResult = service.GetBlogPosts(new GetBlogPostsRequest());
// Assert
//mockFile1.VerifyGet(x => x.FullName, Times.Exactly(5), "FullName should have been called exactly 5 times.");
Assert.NotNull(actualResult.BlogList, "BlogList should not be null");
Assert.NotNull(actualResult.BlogList.BlogPosts, "BlogPosts should not be null");
Assert.True(actualResult.Success, "Success should be true");
Assert.IsNull(actualResult.Message, "Message should be null");
Assert.AreEqual(5, actualResult.BlogList.BlogPosts.Length, "5 blog posts are expected");
Assert.AreEqual(new DateTime(2014, 1, 12, 18, 52, 32), actualResult.BlogList.BlogPosts[0].FileDate, "file3 should be pos 1");
Assert.AreEqual(new DateTime(2013, 12, 28, 4, 31, 41), actualResult.BlogList.BlogPosts[1].FileDate, "file1 should be pos 2");
Assert.AreEqual(new DateTime(2013, 10, 9, 1, 54, 43), actualResult.BlogList.BlogPosts[2].FileDate, "file2 should be pos 3");
Assert.AreEqual(new DateTime(2012, 12, 20, 6, 18, 23), actualResult.BlogList.BlogPosts[4].FileDate, "file4 should be pos 5");
Assert.AreEqual(new DateTime(2013, 6, 4, 12, 28, 56), actualResult.BlogList.BlogPosts[3].FileDate, "file5 should be pos 4");
}
这是实施代码:
public GetBlogPostsResponse GetBlogPosts(GetBlogPostsRequest req)
{
var files = _fs.Directory.GetFiles(contentPath, string.Concat("*", blogFilesExtension));
if (files == null || files.Length <= 0) {
return new GetBlogPostsResponse {
Success = false,
Message = "No blog posts have been made"
};
}
// Deserialize / map each message
var orderedFiles = files
.Select(p => {
var post = _serializer.Deserialize<BlogPostModel>(_fs.File.ReadAllText(p));
post.FileDate = GetFileNameDate(p);
post.FilePath = p;
return post;
})
.OrderByDescending(x => x.FileDate);
var posts = orderedFiles.ToArray();
var response = new GetBlogPostsResponse {
Success = true,
BlogList = new BlogListModel {
// BUG: enumerating here is returning a copy of the last element of the array for all elements
BlogPosts = posts
}
};
return response;
}
我错过了一些明显的东西吗?我检查了所有模拟设置是否正确,上面的调试似乎表明ToArray()方法正在扮演有趣的乞丐......但这是不可能的,对吧? :|
答案 0 :(得分:3)
典型 - 排序了!如果有的话,在SO上张贴让我休息一下,稍后再回来。
这是有道理的,现在我已经弄明白......我修改了以下测试线:
mockSerializer
.Setup(x => x.Deserialize<BlogPostModel>(It.IsAny<string>()))
.Returns(new BlogPostModel());
以下内容:
mockSerializer
.Setup(x => x.Deserialize<BlogPostModel>(It.IsAny<string>()))
.Returns(() => new BlogPostModel());
必须通过普通的lambda覆盖返回新的BlogPostModel()。看起来Moq会重新使用从Setup返回的值,如果你没有明确告诉它每次返回一个唯一值 - 这解释了为什么它总是返回最后一个元素 - 因为枚举的每个元素只是一个引用从Moq返回的对象。
呼!