我有一个存储库,其中包含一些私有方法,以帮助处理需要在该存储库中完成的一些常规内容(不要觉得您需要阅读所有代码) :
public class EFBlogRepository : EFGenericRepository<Blog>, IBlogRepository
{
public EFBlogRepository( EFDbContext context )
: base( context )
{
this.context = context;
}
// Problematic method
private IQueryable<Blog> PrepareAllBlogsQuery( int page, int amount, string sort, string order, ISearchCriteria searchCriteria )
{
var query = context.Blogs
.Where( x => x.DeletedAt == null );
...
return query;
}
public IEnumerable<Blog> GetAllBlogs( int page, int amount, string sort, string order, ISearchCriteria searchCriteria )
{
return this.PrepareAllBlogsQuery( page, amount, sort, order, searchCriteria )
.Skip( ( page - 1 ) * amount )
.Take( amount );
}
public int CountAllBlogs( int page, int amount, string sort, string order, ISearchCriteria searchCriteria )
{
return this.PrepareAllBlogsQuery( page, amount, sort, order, searchCriteria )
.Count();
}
当我尝试进行单元测试时,问题出现了......
我必须制作PrepareAllBlogsQuery public
和virtual
才能使其正常工作(您只需阅读注释位):
// Arrange
DateTime now = DateTime.Now;
var mockDbContext = new Mock<EFDbContext>();
var blogRepository = new Mock<EFBlogRepository>(mockDbContext.Object);
IDbSet<Blog> blogDbSet = new FakeDbSet<Blog>();
List<Blog> blogs = new List<Blog> {
new Blog { BlogID = 1, Description = "1", Status = true, PublishDate = now },
new Blog { BlogID = 2, Description = "2", Status = true, PublishDate = now },
new Blog { BlogID = 3, Description = "3", Status = true, PublishDate = now },
new Blog { BlogID = 4, Description = "4", Status = true, PublishDate = now },
new Blog { BlogID = 5, Description = "5", Status = true, PublishDate = now },
new Blog { BlogID = 6, Description = "6", Status = true, PublishDate = now },
};
IQueryable<Blog> blogsQueryable = blogs.AsQueryable();
mockDbContext.SetupGet(c => c.Blogs).Returns(blogDbSet);
// This Setup requires my method to be public and virtual :(
blogRepository.SetupGet(c => c.PrepareAllBlogsQuery(2, 2, SortDirection.DESC, null, null)).Returns(blogsQueryable);
// Act
List<Blog> result = blogRepository.Object.GetAllBlogs(2, 2, SortDirection.DESC, null, null).ToList();
// Assert
Assert.AreEqual("3", result[0].Description);
有什么方法吗?
我甚至不想测试PrepareAllBlogsQuery
方法,我只需要模拟框架就可以知道该方法返回的内容,无论其内容如何。
答案 0 :(得分:1)
是的,您应该为您的存储库创建一个接口,这是您在单元测试中模拟的东西:
public interface IEFBlogRepository
{
IEnumerable<Blog> GetAllBlogs( int page, int amount, string sort, string order, ISearchCriteria searchCriteria )
}
public class EFBlogRepository : IEFBlogRepository
{
...
}
然后在您的单元测试中,您可以模拟IEFBlogRepository
并且您不需要去EF附近的任何地方。
var mockRepository = new Mock<IEFBlogRepository>();
mockRepository.Setup(r => r.....);
var thing = new Thing(mockRepository.Object);
thing.DoSomeStuffWhichCallsRepository();
<强>更新强>
由于您似乎正在尝试测试EFBlogRepository
,因此您不应该嘲笑该类,您应该使用EFBlogRepository
本身并仅仅模拟其依赖项。虽然我不知道你的FakeDbSet<Blog>
究竟是什么,但你应该可以做这样的事情来获得正确的数据集:
var blogs = new List<Blog> { ... };
var blogDbSet = new FakeDbSet<Blog>(blogs.AsQueryable());
mockDbContext.SetupGet(c => c.Blogs).Returns(blogDbSet);
Blogs为空的原因是因为blogDbSet
实际上并未配置为返回blogsQueryable
答案 1 :(得分:0)
您可以将方法声明为internal,并在您的案例单元测试项目的输出程序集中将内部暴露给特定的Assembly。
需要在正在测试的项目的AssemblyInfo.cs中提及以下属性。
[assembly:InternalsVisibleToAttribute("UnitTestAssemblyName")]
如果命名强烈
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("BoardEx_BusinessObjects.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100fb3a2")]
有一个类似的线程回答相同的click here