使用xunit .NET Core 3.1和Moq的工作单元的单元测试服务。

问题描述 投票:0回答:1

我对xUnit相当陌生,我有一个应用程序,它使用工作单元模式来返回数据到一个服务,我试图对这个服务进行单元测试。

下面是服务代码。

 public async Task<IEnumerable<CatDto>> GetActiveCatsAsync()
    {
        var catList = new List<CatDto>();
        var catEFList = await _uow.Repository<Cat>().GetActiveCatsAsync();
        catList.AddRange(catEFList.Select(c => new CatDto
        {
            CatId = c.CatId,
            CatName = c.CatName,
            DisplayOrd = c.DisplayOrd
        }));


        return catList;
    }

这里是这个服务调用的扩展。

 public static async Task<List<Cat>> GetActiveCatsAsync(this IRepository<Cat> repository)
    {
        return await repository.AsQueryableRepo().Items.Where(c =>c.IsActive == true).OrderBy(c=>c.DisplayOrd).ToListAsync();
    }
}

这是扩展所使用的接口

 internal static IQueryableRepository<T> AsQueryableRepo<T>(this IRepository<T> repository) where T : class
    {
        return (IQueryableRepository<T>)repository;
    }

这里是具体的工作单元类

 public class SQLUnitOfWork<TContext> : BaseUnitOfWork, ISQLUnitOfWork<TContext>
    where TContext : IDbContext, IDisposable
{
    public SQLUnitOfWork(TContext context) : base(context)
    {
    }
}

这是我目前进行的单元测试的情况。

  [Fact]
    public void GetActiveCatsAsync_ReturnsTypeIEnumerableCatDto()
    {
        var mockLogger = new Mock<ILogger<CatService>>();
        var mockUoW = new Mock<ISQLUnitOfWork>();

        var catServ = new CatService(mockLogger.Object, mockUoW.Object);

        var result = catServ.GetActiveCatsAsync();

        Assert.IsType<Task<IEnumerable<CatDto>>>(result);
    }

这个测试实际上是通过了,但是很明显,"结果 "变量中没有数据 因为没有设置mocks。我也试着设置了。

 var mockRepo = new Mock<IRepository<Cat>>();

但这并不能让我进入上面的扩展方法。它没有给我显示 "asQueryableRepo() "方法来提供一个返回值。所以我不知道如何模拟返回数据,这将是一个简单的Cat对象,在服务调用中显示了三个属性。我也尝试过使用xUnit的.ReturnAsync()和Task.FromResult()功能。

经过几次搜索,我尝试实现xUnit.DependencyInjection,但这需要在测试项目的Startup.cs文件中进行配置。我的测试项目(用Visual Studio xUnit项目模板创建)没有Startup.cs文件。难道我用错了模板?

我也见过类似下面使用的东西。

      scope = new CustomWebApplicationFactory<Startup>().Server.Host.Services.CreateScope();
service = scope.ServiceProvider.GetRequiredService<IDashboardService>();
context = scope.ServiceProvider.GetRequiredService<DTBContext>();

这似乎也是引用了一个启动类 所以我也没能让这个方法成功。我是否需要重新开始一个包含Startup.cs文件夹的项目?还是说我可以不用上面的代码进行单元测试?我还在研究这个问题,但到目前为止,我找不到一种方法来模拟服务调用和工作单元元素的依赖关系。

任何建议或意见都非常感谢! 谢谢您

更新:我想我现在理解了xUnit.DependencyInjection,所以我添加了一个startup.cs类,并添加了他们GitHub页面上提到的引用。我还不得不安装Microsoft.Extensions.Hosting包来处理一个 "没有实现 "的错误,现在我的项目有了一个启动器,上面通过的测试现在也通过了。我希望现在我可以在测试项目中处理依赖关系,但我会发现。

c# unit-testing moq xunit unit-of-work
1个回答
0
投票

你可以尝试使用 As:

[Fact]
public async Task GetActiveCatsAsync_ReturnsTypeIEnumerableCatDto()
{
    var mockLogger = new Mock<ILogger<CatService>>();
    var mockRepo = new Mock<IRepository<Cat>>();
    var cat = new Cat
    {
        IsActive = true
    };
    mockRepo
        .As<IQueryableRepository<Cat>>()
        .Setup(x => x.Items)
        .Returns(x => new[] { cat }.AsQueryable);
    var mockUoW = new Mock<ISQLUnitOfWork>();
    mockUoW.Setup(x => x.Repository<Cat>()).Returns(mockRepo.Object);
    var catServ = new CatService(mockLogger.Object, mockUoW.Object);

    var result = await catServ.GetActiveCatsAsync();

    var single = Assert.Single(result);
    Assert.Equal(cat, single);
}

更新。

是的,测试实体框架是一个单独的问题。在这种情况下,我建议单独测试版本库,使用 InMemoroyDatabase 或其他什么东西,这就不适合拉到服务测试中去。

为了真正测试服务是否在做它应该做的事情,理想情况下,你应该像这样验证。

[Fact]
public async Task GetActiveCatsAsync_ReturnsTypeIEnumerableCatDto()
{
    var mockLogger = new Mock<ILogger<CatService>>();
    var mockRepo = new Mock<IRepository<Cat>>();
    var mockUoW = new Mock<ISQLUnitOfWork>();
    mockUoW.Setup(x => x.Repository<Cat>()).Returns(mockRepo.Object);
    var catServ = new CatService(mockLogger.Object, mockUoW.Object);

    var result = await catServ.GetActiveCatsAsync();

    mockRepo.Verify(x => x.GetActiveCatsAsync(), Times.Once);
}

但你无法在扩展方法上做到这一点 But you won't be able to do this on an extension method. 不幸的是,你要测试的代码并不适合轻松地针对它编写纯单元测试。具体来说,让UoW暴露仓库是很麻烦的。如果让 ISQLUnitOfWork 有自己 GetActiveCatsAsync 方法,这样仓库就不可见了(泄漏的抽象)--这样你就可以直接在UoW上进行验证。

mockUoW.Verify(x => x.GetActiveCatsAsync(), Times.Once);
© www.soinside.com 2019 - 2024. All rights reserved.