我必须使一种方法公开和虚拟才能使用最小起订量设置

本文关键字:虚拟 设置 方法 一种 | 更新日期: 2023-09-27 17:56:57

我有一个仓库,里面有一些私有方法来帮助完成一些需要在该仓库中完成的一般工作(不要觉得你需要阅读所有代码):

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 publicvirtual才能使其工作(您只需要阅读注释位):

// 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 方法,我只需要模拟框架来知道该方法返回的内容,无论其内容如何。

我必须使一种方法公开和虚拟才能使用最小起订量设置

是的,你应该为你的仓库创建一个接口,这是你在单元测试中模拟的东西:

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);

博客对您来说为空的原因是blogDbSet实际上并未配置为返回blogsQueryable

可以将该方法声明为内部方法,并在事例单元测试项目的输出程序集中向特定程序集公开内部组件。

以下属性需要在正在测试的项目的AssemblyInfo.cs中提及。 [assembly:InternalsVisibleToAttribute("UnitTestAssemblyName")]

在强命名的情况下

[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("BoardEx_BusinessObjects.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100fb3a2")]

有一个类似的线程回答相同的单击此处