You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GitHub Actions中使用serilog.json配置文件时出现错误

.NET Core项目GitHub Actions单元测试失败问题

本地执行dotnet test时所有测试正常,但推送代码后GitHub Actions中有2个测试失败,报错找不到Serilog配置文件。

错误信息

Error Message:
System.IO.FileNotFoundException : The configuration file 'AnimeViewedDiary.Infrastructure\serilog.json' was not found and is not optional. The expected physical path was '/home/runner/work/animeViewedDiary/animeViewedDiary/src/AnimeViewedDiary.Infrastructure\serilog.json'.
Stack Trace:
at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load(Boolean reload)
at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers)
at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()

项目结构与相关代码

  • serilog.json路径:src/AnimeViewDiary.Infrastucture/serilog.json
  • 测试文件路径:tests/AnimeViewDiary.Data.UnitTests/
  • UnitOfWork文件路径:src/AnimeViewDiary.Data/Repositories/Based/UnitOfWork.cs

失败的测试代码

[Fact]
public void SaveChanges_SuccessSaveChanges_SaveChanges()
{
    // Arrange
    Mock<DiaryApplicationDbContext> mockApplicationDbContext =
        UnitOfWorkConfiguration.CreateMockApplicationDbContext();
    Mock<DiaryIdentityDbContext> mockIdentityDbContext =
        UnitOfWorkConfiguration.CreateMockIdentityDbContext();

    IUnitOfWork unitOfWork = new UnitOfWork(mockIdentityDbContext.Object,
        mockApplicationDbContext.Object);

    // Act
    unitOfWork.SaveChanges();

    // Assert
    mockApplicationDbContext.Verify(options => options.SaveChanges(), Times.Once);
    mockIdentityDbContext.Verify(options => options.SaveChanges(), Times.Once);
}

UnitOfWork构造函数代码

public UnitOfWork(DiaryIdentityDbContext identityDbContext, DiaryApplicationDbContext applicationDbContext)
{
    string currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory()).Name;
    
    const string projectName = "AnimeViewedDiary.Infrastructure";
    const string projectApiName = "AnimeViewedDiary.WebAPI";
    const string serilogFileName = "serilog.json";
    const string srcDirectoryName = "src";
    
    string srcFolderPath;
    
    if (currentDirectory == projectApiName)
        srcFolderPath = Directory.GetParent(currentDirectory)?.Parent?.ToString()!;
    else
    {
        string rootDirectory = new DirectoryInfo(currentDirectory).Parent?.Parent?.Parent?.Parent?.Parent?.Parent
            ?.ToString()!;
        srcFolderPath = Path.Combine(rootDirectory, srcDirectoryName);
    }
    
    string fullPath = Path.Combine(srcFolderPath, projectName) + "\\";
    string pathToFile = fullPath + serilogFileName;
    
    IConfigurationRoot configuration = new ConfigurationBuilder()
        .AddJsonFile(pathToFile, optional: false, reloadOnChange: true)
        .Build();
    
    ILogger logger = new LoggerConfiguration()
        .ReadFrom.Configuration(configuration)
        .CreateLogger();

    _identityDbContext = identityDbContext;
    _applicationDbContext = applicationDbContext;
    UserRepository = new UserRepository(_identityDbContext, logger);
}

GitHub Actions工作流配置

name: Build and Testing .NET AnimeViewedDiary Project

on:
  push:
    branches:
      - "*"
      - "*/*"
      - "**"
  pull_request:
    branches:
      - "*"
      - "*/*"
      - "**"

jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        dotnet-version: ["7.0.x"]

    steps:
      - uses: actions/checkout@v3

      - name: Setup .NET Core SDK ${{ matrix.dotnet-version }}
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: ${{ matrix.dotnet-version }}
          
      - name: Restore/Install dependencies
        run: dotnet restore

      - name: Build project
        run: dotnet build --configuration Release --no-restore
        
      - name: Unit tests
        run: dotnet test

问题原因与解决方法

问题原因

  1. 路径分隔符不兼容:代码硬编码了Windows风格的\\分隔符,而GitHub Actions使用Ubuntu系统(Linux),默认用/分隔符,导致生成的路径混合两种格式,系统无法识别。
  2. 目录层级依赖不可靠:通过多次调用Parent获取根目录,这种方式依赖当前执行目录的层级,本地与GitHub Actions的执行目录结构不一致,导致路径计算错误。
  3. 测试耦合外部依赖:单元测试中直接读取真实配置文件,既耦合环境,又可能因为配置文件未复制到测试输出目录导致找不到。

解决方法

方法一:修复路径处理逻辑(临时方案)

  • 避免硬编码路径分隔符,改用Path.Combine自动适配系统:
    将原代码中:
    string fullPath = Path.Combine(srcFolderPath, projectName) + "\\";
    string pathToFile = fullPath + serilogFileName;
    
    修改为:
    string pathToFile = Path.Combine(srcFolderPath, projectName, serilogFileName);
    
  • 优化目录获取逻辑,避免多层Parent调用,比如通过查找解决方案文件定位根目录,或使用相对路径。

方法二:重构代码解耦日志依赖(推荐方案)

单元测试应隔离外部依赖,通过依赖注入传入Mock日志对象:

  1. 修改UnitOfWork构造函数,直接接收ILogger参数:
    public UnitOfWork(DiaryIdentityDbContext identityDbContext, 
                      DiaryApplicationDbContext applicationDbContext,
                      ILogger<UserRepository> logger)
    {
        _identityDbContext = identityDbContext;
        _applicationDbContext = applicationDbContext;
        UserRepository = new UserRepository(_identityDbContext, logger);
    }
    
  2. 在WebAPI项目的DI容器中配置Serilog,运行时注入真实日志:
    // Program.cs中
    builder.Host.UseSerilog((context, config) => 
        config.ReadFrom.Configuration(context.Configuration));
    
  3. 单元测试中创建Mock日志对象传入:
    [Fact]
    public void SaveChanges_SuccessSaveChanges_SaveChanges()
    {
        // Arrange
        Mock<DiaryApplicationDbContext> mockApplicationDbContext =
            UnitOfWorkConfiguration.CreateMockApplicationDbContext();
        Mock<DiaryIdentityDbContext> mockIdentityDbContext =
            UnitOfWorkConfiguration.CreateMockIdentityDbContext();
        var mockLogger = new Mock<ILogger<UserRepository>>();
    
        IUnitOfWork unitOfWork = new UnitOfWork(mockIdentityDbContext.Object,
            mockApplicationDbContext.Object, mockLogger.Object);
    
        // Act
        unitOfWork.SaveChanges();
    
        // Assert
        mockApplicationDbContext.Verify(options => options.SaveChanges(), Times.Once);
        mockIdentityDbContext.Verify(options => options.SaveChanges(), Times.Once);
    }
    

方法三:确保配置文件复制到测试输出目录

如果必须使用真实配置文件,修改AnimeViewDiary.Infrastructure项目的serilog.json属性:

  • 在Visual Studio中右键文件→属性,设置“复制到输出目录”为“如果较新则复制”;
  • 或直接在项目文件(.csproj)中添加:
    <ItemGroup>
      <None Update="serilog.json">
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      </None>
    </ItemGroup>
    
    之后通过Directory.GetCurrentDirectory()结合相对路径读取文件。

内容的提问来源于stack exchange,提问作者saibel203

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 05:14:55