C# 在.NET Core中使用xUnit、Moq和repository模式测试服务层

C# 在.NET Core中使用xUnit、Moq和repository模式测试服务层,c#,unit-testing,.net-core,moq,xunit,C#,Unit Testing,.net Core,Moq,Xunit,我正在构建一个简单的.NETCoreWebAPI应用程序,其中有一个后台任务,可以从网站下载一些CSV文件,并将它们保存到数据库中(使用EFCore)。另一个后台任务将负责处理它们。 这只是一个演示应用程序,让我熟悉.NET核心Web Api、EF核心、Moq、xUnit和存储库/服务/工作单元模式 我已经编写了业务逻辑,它运行良好,但现在我还想进行测试 这是我为了测试排队功能而编写的测试:它非常简单。我检查文件是否已经排队(针对特定日期),如果没有,我将其排队 [Fact] p

我正在构建一个简单的.NETCoreWebAPI应用程序,其中有一个后台任务,可以从网站下载一些CSV文件,并将它们保存到数据库中(使用EFCore)。另一个后台任务将负责处理它们。 这只是一个演示应用程序,让我熟悉.NET核心Web Api、EF核心、Moq、xUnit和存储库/服务/工作单元模式

我已经编写了业务逻辑,它运行良好,但现在我还想进行测试

这是我为了测试排队功能而编写的测试:它非常简单。我检查文件是否已经排队(针对特定日期),如果没有,我将其排队

    [Fact]
    public void TestQueueFileForProcessingWhenNotYetQueued()
    {
        string alreadyQueuedFile = "Estrazione del 2019-01-02";
        var mockUnitOfWork = new Mock<IUnitOfWork>();
        var gasStationExternalFileRepository = new Mock<IGasStationExternalFileRepository>();
        var service = new GasStationExternalFileService(mockUnitOfWork.Object, gasStationExternalFileRepository.Object);
        gasStationExternalFileRepository.Setup(x => x.HasFileAlreadyBeenQueued(new DateTime(2019, 01, 02))).Returns(false);

        var result = service.QueueFileForProcessing(Encoding.UTF8.GetBytes(alreadyQueuedFile));
        Assert.True(result, "Object has been queued now");

        var expectedFile = gasStationExternalFileRepository.Object.SingleOrDefault(x => x.ReferenceDate.Date == new DateTime(2019, 01, 02));
        Assert.NotNull(expectedFile);
        Assert.Equal(Encoding.UTF8.GetBytes(alreadyQueuedFile), expectedFile.Content);
        Assert.Null(expectedFile.ProcessingDate);
        Assert.Equal(Core.Reference.ProcessingStatus.Queued, expectedFile.ProcessingStatus);
        Assert.Equal(new DateTime(2019, 01, 02), expectedFile.ReferenceDate);
    }
我在等那个文件

        var expectedFile = gasStationExternalFileRepository.Object.SingleOrDefault(x => x.ReferenceDate.Date == new DateTime(2019, 01, 02));
不为空。但它总是空的

我错过了什么

编辑:这是正在测试的主题

        public class GasStationExternalFileRepository : Repository<GasStationsExternalFile, DbContext>, IGasStationExternalFileRepository
        {
            public GasStationExternalFileRepository(DbContext context) : base(context)
            {
            }

            public bool HasFileAlreadyBeenQueued(DateTime referenceDate)
            {
                return Entities.Where(x => x.ReferenceDate.Date == referenceDate).Select(x => x.Id).Any();
            }
        }


public abstract class Repository<TEntity, TContext> : IRepository<TEntity>
    where TEntity : class, IEntity
    where TContext : DbContext
{
    public Repository(TContext context)
    {
        Entities = context.Set<TEntity>();
    }

    protected DbSet<TEntity> Entities { get; }

    public TEntity Get(Guid id)
    {
        return Entities.Find(id);
    }

    public IEnumerable<TEntity> GetAll()
    {
        return Entities.ToList();
    }

    public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
    {
        return Entities.Where(predicate);
    }

    public TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate)
    {
        return Entities.SingleOrDefault(predicate);
    }

    public void Add(TEntity entity)
    {
        Entities.Add(entity);
    }

    public void AddRange(IEnumerable<TEntity> entities)
    {
        Entities.AddRange(entities);
    }

    public void Remove(TEntity entity)
    {
        Entities.Remove(entity);
    }

    public void RemoveRange(IEnumerable<TEntity> entities)
    {
        Entities.RemoveRange(entities);
    }
}
公共类GassStationExternalFileRepository:Repository,IGasStationExternalFileRepository
{
public GasStationExternalFileRepository(DbContext上下文):基础(上下文)
{
}
public bool HasFileAlreadyBeenQueued(日期时间引用日期)
{
返回Entities.Where(x=>x.ReferenceDate.Date==ReferenceDate).Select(x=>x.Id).Any();
}
}
公共抽象类存储库:IRepository
其中tenty:类,tenty
其中TContext:DbContext
{
公共存储库(TContext上下文)
{
Entities=context.Set();
}
受保护的数据库集实体{get;}
公共权限获取(Guid id)
{
返回实体。查找(id);
}
公共IEnumerable GetAll()
{
返回实体。ToList();
}
公共IEnumerable查找(表达式谓词)
{
返回实体。其中(谓词);
}
公共TEntity SingleOrDefault(表达式谓词)
{
返回实体。SingleOrDefault(谓词);
}
公共无效添加(TEntity实体)
{
实体。添加(实体);
}
公共void AddRange(IEnumerable实体)
{
实体。添加范围(实体);
}
公共无效删除(TEntity实体)
{
实体。移除(实体);
}
公共无效删除范围(IEnumerable实体)
{
实体。删除范围(实体);
}
}

gasStationExternalFileRepository
是一个模拟文件。测试返回null是有意义的,因为它没有设置为包含任何数据。测试模拟对象也是没有意义的。显示被测试的主题以及您实际想要实现的内容。请参阅最后一个编辑我想要实现的是:调用gasStationExternalFileRepository.object.SingleOrDefault(x=>x.ReferenceDate.Date==new DateTime(2019,01,02));返回我在我的业务逻辑中添加到它的对象。您应该只测试
GasStationExternalFileService
的方法/属性。您的
GassStationExternalFileRepository
不是一个存储库,它只是一个存根对象,以满足您的服务对
IGasStationExternalFileRepository
的需求。只要假设
.Add(file)
在单元测试中起作用,因为这不是测试的内容。存储库的实现应该有自己的单元测试。
        public class GasStationExternalFileRepository : Repository<GasStationsExternalFile, DbContext>, IGasStationExternalFileRepository
        {
            public GasStationExternalFileRepository(DbContext context) : base(context)
            {
            }

            public bool HasFileAlreadyBeenQueued(DateTime referenceDate)
            {
                return Entities.Where(x => x.ReferenceDate.Date == referenceDate).Select(x => x.Id).Any();
            }
        }


public abstract class Repository<TEntity, TContext> : IRepository<TEntity>
    where TEntity : class, IEntity
    where TContext : DbContext
{
    public Repository(TContext context)
    {
        Entities = context.Set<TEntity>();
    }

    protected DbSet<TEntity> Entities { get; }

    public TEntity Get(Guid id)
    {
        return Entities.Find(id);
    }

    public IEnumerable<TEntity> GetAll()
    {
        return Entities.ToList();
    }

    public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
    {
        return Entities.Where(predicate);
    }

    public TEntity SingleOrDefault(Expression<Func<TEntity, bool>> predicate)
    {
        return Entities.SingleOrDefault(predicate);
    }

    public void Add(TEntity entity)
    {
        Entities.Add(entity);
    }

    public void AddRange(IEnumerable<TEntity> entities)
    {
        Entities.AddRange(entities);
    }

    public void Remove(TEntity entity)
    {
        Entities.Remove(entity);
    }

    public void RemoveRange(IEnumerable<TEntity> entities)
    {
        Entities.RemoveRange(entities);
    }
}