如何解决如何使用 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 举报,一经查实,本站将立刻删除。