如何使用 moq 和 xunit 测试业务逻辑方法?

如何解决如何使用 moq 和 xunit 测试业务逻辑方法?

我正在使用通用存储库模式和 这段代码来自我的业务逻辑。

public class FolderManager : GenericManager<Folder>,IFolderService
{
    private readonly IGenericDal<Folder> _genericDal;
    private readonly IFolderDal _folderDal;
    public FolderManager(IFolderDal folderDal,IGenericDal<Folder> genericDal) : base(genericDal)
    {
        _genericDal = genericDal;
        _folderDal = folderDal;
    }

    public async Task<List<Folder>> GetFoldersByUserId(int id)
    {
        return await _genericDal.GetAllByFilter(I => I.AppUserId == id && I.IsDeleted == false && I.ParentFolderId==null);
    } ...another methods

IFolderService 接口:

public interface IFolderService : IGenericService<Folder>
{
    Task<List<Folder>> GetFoldersByUserId(int id);
}     ...another methods

我想测试 GetFoldersByUserId(int id) 方法,我试过了:

public class FolderServiceTest
{  
    private readonly FolderManager _sut;
    private readonly Mock<IGenericDal<Folder>> _folderRepoMock = new Mock<IGenericDal<Folder>>();
    private readonly Mock<IFolderDal> _folderDalMock = new Mock<IFolderDal>();
    public FolderServicetest()
    {
        _sut = new FolderManager(_folderDalMock.Object,_folderRepoMock.Object);
    }

    [Fact]
    public async Task GetFoldersByUserId_ShouldReturnlistofFolders_WhenUserExist()
    {
        //Arrange
        Mock<IFolderService> folderServiceMock = new Mock<IFolderService>();
        folderServiceMock.Setup(x => x.GetFoldersByUserId(It.IsAny<int>())).ReturnsAsync(GetSampleFolder);
        
        var expected = GetSampleFolder();

        //Act
         
        //returns null beacuse _sut does not work with the setup I wrote above
        //how can i test this method ? 
        var actual = await _sut.GetFoldersByUserId(1); /* */

        //Assert 
        Assert.Equal(expected.Count,actual.Count);

        for (int i = 0; i < expected.Count; i++)
        {
            Assert.Equal(expected[i].FolderName,actual[i].FolderName);
            Assert.Equal(expected[i].Size,actual[i].Size);
        } 
    }

当我开始测试时,实际值为空,测试失败。 GetSampleFolder 方法一个文件夹列表并返回这个列表。我的问题是如何测试 GetFoldersByUserId(int id) 方法

解决方法

下面的测试展示了如何适当地设置模拟。

棘手的部分是表达式匹配,Moq 不支持。 这就是我在那里使用 It.IsAny 匹配器的原因。

[Fact]
public async Task GetFoldersByUserId_ShouldReturnListOfFolders_WhenUserExist()
{
    //Arrange
    var expected = GetSampleFolder();

    var _folderRepoMock = new Mock<IGenericDal<Folder>>();
    _folderRepoMock
        .Setup(x => x.GetAllByFilter(It.IsAny<Expression<Func<Folder,bool>>>()))
        .ReturnsAsync(expected);

    var _folderDalMock = new Mock<IFolderDal>();

    var _sut = new FolderManager(_folderDalMock.Object,_folderRepoMock.Object);


    //Act
    var actual = await _sut.GetFoldersByUserId(1);

    //Assert 
    Assert.Equal(expected.Count,actual.Count);

    for (int i = 0; i < expected.Count; i++)
    {
        Assert.Equal(expected[i].FolderName,actual[i].FolderName);
        Assert.Equal(expected[i].Size,actual[i].Size);
    }
}

如果您真的想测试由 GetAllByFilter 交给 GetFoldersByUserId 的表达式的正确性,您需要做一些额外的工作。 我个人曾经根据您的测试用例而不是 It.IsAny... 来匹配 expression.ToString() 结果:

Is.Is<Expression<Func<Folder,bool>>>(exp => exp.ToString() == "I => I.AppUserId == 1 && I.IsDeleted == false && I.ParentFolderId==null")

但要使其工作,您应该先对表达式进行部分评估,然后将封装的变量引用和常量引用显式替换为实际值。如果没有这一步,exp.ToString() 将如下所示:

I => (((I.AppUserId == value(StackOverflow.UnitTest1+FolderManager+<>c__DisplayClass3_0).id) AndAlso (I.IsDeleted == False)) AndAlso (I.ParentFolderId == null))

其中 StackOverflow.UnitTest1+FolderManager 之类的东西将是引导实际封装的 id 变量在代码中的位置的部分。

您可以随时修改测试以实际使用表达式而不是对其进行匹配,而不是使用 exp.ToString() 方法:

// just populate to cover all special cases
private List<Folder> testFolderList = new List<Folder>()
{
    new Folder() { AppUserId=1,IsDeleted=false,ParentFolderId=null,FolderName = "a",Size = 1 },new Folder() { AppUserId=1,IsDeleted=true,FolderName = "b",Size = 2 },ParentFolderId=2,FolderName = "c",Size = 3 },new Folder() { AppUserId=2,Size = 4 },};


[Fact]
public async Task GetFoldersByUserId_ShouldReturnListOfFolders_WhenUserExist()
{
    //Arrange
    var userId = 1;
    var expected = testFolderList
        // replace with expression based on the _contract_ you expect from GetFoldersByUserId
        .Where(I => I.AppUserId == userId && I.IsDeleted == false && I.ParentFolderId == null) 
        .ToList();

    var _folderRepoMock = new Mock<IGenericDal<Folder>>();
    _folderRepoMock
        .Setup(x => x.GetAllByFilter(It.IsAny<Expression<Func<Folder,bool>>>()))
        .ReturnsAsync((Expression<Func<Folder,bool>> exp) =>
        {
            return testFolderList
                // here we explicitly use the expression we got as parameter
                .Where(exp.Compile())
                .ToList();
        });

    var _folderDalMock = new Mock<IFolderDal>();

    var _sut = new FolderManager(_folderDalMock.Object,_folderRepoMock.Object);


    //Act
    var actual = await _sut.GetFoldersByUserId(userId);

    //Assert 
    Assert.Equal(expected.Count,actual[i].Size);
    }
}

通过这种方式,可以根据测试数据对构造表达式的适当性进行测试。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?