WIP: 单元测试

Reviewing AudioMetadataReader.cs
This commit is contained in:
2026-04-17 14:20:03 +08:00
parent 20ae0909cf
commit 021f4b1cd1
13 changed files with 641 additions and 144 deletions
+59
View File
@@ -0,0 +1,59 @@
namespace OCES.Resonance.Core.Tests;
/// <summary>
/// AudioFileScanner 单元测试
/// </summary>
public class AudioFileScannerTests
{
[Theory]
[InlineData("test.wav", true)]
[InlineData("test.WAV", true)]
[InlineData("test.mp3", true)]
[InlineData("test.txt", false)]
[InlineData("", false)]
[InlineData("test.xlsx", false)]
public void IsSupportedAudioFile_ShouldWork(string input, bool expected)
{
AudioFileScanner scanner = new();
bool result = scanner.IsSupportedAudioFile(input);
Assert.Equal(expected, result);
}
[Fact]
public void ScanDirectory_ShouldWork()
{
string tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(tempDir);
try
{
// 构造真实文件
File.WriteAllText(Path.Combine(tempDir, "a.wav"), "");
File.WriteAllText(Path.Combine(tempDir, "b.MP3"), "");
File.WriteAllText(Path.Combine(tempDir, "c.txt"), "");
File.WriteAllText(Path.Combine(tempDir, "d.xlsx"), "");
File.WriteAllText(Path.Combine(tempDir, "e.WAV"), "");
AudioFileScanner scanner = new();
List<string> result = scanner.ScanDirectory(tempDir).ToList();
Assert.Equal(3, result.Count);
}
finally
{
Directory.Delete(tempDir, true);
}
}
[Fact]
public void ScanDirectory_ShouldThrow_WhenDirectoryDoesNotExist()
{
AudioFileScanner scanner = new();
string nonExistentPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Assert.Throws<DirectoryNotFoundException>(() => scanner.ScanDirectory(nonExistentPath));
}
}
+133
View File
@@ -0,0 +1,133 @@
using FluentAssertions;
namespace OCES.Resonance.Core.Tests;
/// <summary>
/// AudioLibraryService 集成测试
/// </summary>
public class AudioLibraryServiceTests : IDisposable
{
readonly AudioLibraryService _service;
readonly string _testDirectory;
public AudioLibraryServiceTests()
{
_service = new AudioLibraryService();
_testDirectory = Path.Combine(Path.GetTempPath(), $"LibraryServiceTest_{Guid.NewGuid()}");
Directory.CreateDirectory(_testDirectory);
}
public void Dispose()
{
if (Directory.Exists(_testDirectory))
{
Directory.Delete(_testDirectory, true);
}
// 清理测试数据库
var dbPath = "default.db";
if (File.Exists(dbPath))
{
File.Delete(dbPath);
}
}
[Fact]
public async Task ScanAndImportToLibrary_空目录_返回零总数()
{
// Act
var result = await _service.ScanAndImportToLibrary(_testDirectory);
// Assert
result.TotalFiles.Should().Be(0);
result.SuccessCount.Should().Be(0);
result.ErrorCount.Should().Be(0);
}
[Fact]
public async Task ScanAndImportToLibrary_包含音频文件_成功导入()
{
// Arrange
var wavFile = Path.Combine(_testDirectory, "test.wav");
File.WriteAllText(wavFile, "fake wav content");
// Act
var result = await _service.ScanAndImportToLibrary(_testDirectory);
// Assert
result.TotalFiles.Should().Be(1);
result.SuccessCount.Should().Be(1);
result.ErrorCount.Should().Be(0);
}
[Fact]
public async Task ScanAndImportToLibrary_多个文件_正确统计()
{
// Arrange
File.WriteAllText(Path.Combine(_testDirectory, "audio1.wav"), "fake");
File.WriteAllText(Path.Combine(_testDirectory, "audio2.mp3"), "fake");
File.WriteAllText(Path.Combine(_testDirectory, "audio3.flac"), "fake");
File.WriteAllText(Path.Combine(_testDirectory, "document.txt"), "not audio");
// Act
var result = await _service.ScanAndImportToLibrary(_testDirectory);
// Assert
result.TotalFiles.Should().Be(3);
result.SuccessCount.Should().Be(3);
}
[Fact]
public async Task ScanAndImportToLibrary_递归扫描子目录()
{
// Arrange
var subDir = Path.Combine(_testDirectory, "subdir");
Directory.CreateDirectory(subDir);
File.WriteAllText(Path.Combine(_testDirectory, "root.wav"), "fake");
File.WriteAllText(Path.Combine(subDir, "sub.wav"), "fake");
// Act
var result = await _service.ScanAndImportToLibrary(_testDirectory);
// Assert
result.TotalFiles.Should().Be(2);
result.SuccessCount.Should().Be(2);
}
[Fact]
public void ScanResult_GetSummary_返回正确格式()
{
// Arrange
var result = new ScanResult
{
TotalFiles = 10,
SuccessCount = 8,
SkipCount = 1,
ErrorCount = 1,
};
// Act
var summary = result.GetSummary();
// Assert
summary.Should().Contain("10");
summary.Should().Contain("8");
summary.Should().Contain("1");
}
[Fact]
public async Task ScanAndImportToLibrary_包含不支持格式_只导入音频()
{
// Arrange
File.WriteAllText(Path.Combine(_testDirectory, "audio.wav"), "fake");
File.WriteAllText(Path.Combine(_testDirectory, "image.jpg"), "fake");
File.WriteAllText(Path.Combine(_testDirectory, "doc.pdf"), "fake");
File.WriteAllText(Path.Combine(_testDirectory, "text.txt"), "fake");
// Act
var result = await _service.ScanAndImportToLibrary(_testDirectory);
// Assert
result.TotalFiles.Should().Be(1);
result.SuccessCount.Should().Be(1);
}
}
+130
View File
@@ -0,0 +1,130 @@
using FluentAssertions;
namespace OCES.Resonance.Core.Tests;
/// <summary>
/// AudioMetadataReader 单元测试
/// </summary>
public class AudioMetadataReaderTests
{
readonly AudioMetadataReader _reader;
readonly string _testDirectory;
public AudioMetadataReaderTests()
{
this._reader = new AudioMetadataReader();
this._testDirectory = Path.Combine(Path.GetTempPath(), $"MetadataReaderTest_{Guid.NewGuid()}");
Directory.CreateDirectory(this._testDirectory);
}
[Fact]
public void ReadMetadata_文件不存在_抛出FileNotFoundException()
{
// Arrange
string nonExistentFile = Path.Combine(this._testDirectory, "non_existent.wav");
// Act & Assert
Func<AudioFileMeta> act = () => this._reader.ReadMetadata(nonExistentFile);
act.Should().Throw<FileNotFoundException>();
}
[Fact]
public void ReadMetadata_空文件_仍然返回元数据()
{
// Arrange
string emptyFile = Path.Combine(this._testDirectory, "empty.wav");
File.WriteAllText(emptyFile, "");
// Act
AudioFileMeta result = this._reader.ReadMetadata(emptyFile);
// Assert
result.Should().NotBeNull();
result.Filename.Should().Be("empty.wav");
result.Path.Should().Be(Path.GetFullPath(emptyFile));
result.Md5.Should().NotBeNullOrEmpty();
result.UniqueId.Should().NotBeNullOrEmpty();
}
[Fact]
public void ReadMetadata_生成唯一ID_每次调用都不同()
{
// Arrange
string testFile = Path.Combine(this._testDirectory, "test.wav");
File.WriteAllText(testFile, "fake audio content");
// Act
AudioFileMeta result1 = this._reader.ReadMetadata(testFile);
AudioFileMeta result2 = this._reader.ReadMetadata(testFile);
// Assert
result1.UniqueId.Should().NotBe(result2.UniqueId);
}
[Fact]
public void ReadMetadata_相同文件_MD5相同()
{
// Arrange
var testFile = Path.Combine(this._testDirectory, "test.wav");
File.WriteAllText(testFile, "fake audio content");
// Act
var result1 = this._reader.ReadMetadata(testFile);
var result2 = this._reader.ReadMetadata(testFile);
// Assert
result1.Md5.Should().Be(result2.Md5);
}
[Theory]
[InlineData(".wav", "WAV")]
[InlineData(".mp3", "MP3")]
[InlineData(".flac", "FLAC")]
[InlineData(".aiff", "AIFF")]
public void ReadMetadata_不同格式_正确设置Type字段(string extension, string expectedType)
{
// Arrange
string testFile = Path.Combine(this._testDirectory, $"test{extension}");
File.WriteAllText(testFile, "fake audio content");
// Act
AudioFileMeta result = this._reader.ReadMetadata(testFile);
// Assert
result.Type.Should().Be(expectedType);
}
[Fact]
public void ReadMetadata_提取文件夹信息()
{
// Arrange
string subDir = Path.Combine(this._testDirectory, "SubFolder");
Directory.CreateDirectory(subDir);
string testFile = Path.Combine(subDir, "test.wav");
File.WriteAllText(testFile, "fake audio content");
// Act
AudioFileMeta result = this._reader.ReadMetadata(testFile);
// Assert
result.Folder.Should().Be("SubFolder");
result.Directory.Should().Be(subDir);
}
[Fact]
public void ReadMetadata_设置DateAdded为当前时间()
{
// Arrange
string testFile = Path.Combine(this._testDirectory, "test.wav");
File.WriteAllText(testFile, "fake audio content");
DateTime beforeTime = DateTime.Now;
// Act
AudioFileMeta result = this._reader.ReadMetadata(testFile);
DateTime afterTime = DateTime.Now;
// Assert
result.DateAdded.Should().BeOnOrAfter(beforeTime);
result.DateAdded.Should().BeOnOrBefore(afterTime);
}
}
+27
View File
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4" />
<PackageReference Include="FluentAssertions" Version="8.9.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Core\Core.csproj" />
</ItemGroup>
</Project>
+177
View File
@@ -0,0 +1,177 @@
using System.Data.SQLite;
using FluentAssertions;
namespace OCES.Resonance.Core.Tests;
/// <summary>
/// Database 单元测试
/// </summary>
public class DatabaseTests : IDisposable
{
readonly string _testDbName;
readonly string _testDbPath;
public DatabaseTests()
{
_testDbName = $"test_{Guid.NewGuid():N}";
_testDbPath = $"{_testDbName}.db";
}
public void Dispose()
{
if (File.Exists(_testDbPath))
{
File.Delete(_testDbPath);
}
}
[Fact]
public void GetConnection_返回有效连接()
{
// Act
using var connection = Database.GetConnection(_testDbName);
// Assert
connection.Should().NotBeNull();
connection.Should().BeOfType<SQLiteConnection>();
}
[Fact]
public void InitializeDatabase_创建表结构()
{
// Act
Database.InitializeDatabase();
// Assert - 验证表已创建(通过尝试查询)
using var connection = Database.GetConnection();
connection.Open();
var command = connection.CreateCommand();
command.CommandText = "SELECT COUNT(*) FROM audio_files;";
var count = command.ExecuteScalar();
count.Should().NotBeNull();
}
[Fact]
public void AddEntry_添加有效记录_返回True()
{
// Arrange
Database.InitializeDatabase();
var meta = CreateTestMeta();
// Act
var result = Database.AddEntry(meta);
// Assert
result.Should().BeTrue();
}
[Fact]
public void AddEntry_添加记录后_可以查询到()
{
// Arrange
Database.InitializeDatabase();
var meta = CreateTestMeta();
// Act
Database.AddEntry(meta);
// Assert
using var connection = Database.GetConnection();
connection.Open();
var command = connection.CreateCommand();
command.CommandText = "SELECT filename FROM audio_files WHERE unique_id = @id;";
var param = command.CreateParameter();
param.ParameterName = "@id";
param.Value = meta.UniqueId;
command.Parameters.Add(param);
var filename = command.ExecuteScalar() as string;
filename.Should().Be(meta.Filename);
}
[Fact]
public void AddEntries_批量添加_返回正确数量()
{
// Arrange
Database.InitializeDatabase();
var entries = new List<AudioFileMeta>
{
CreateTestMeta("file1.wav"),
CreateTestMeta("file2.wav"),
CreateTestMeta("file3.wav"),
};
// Act
var count = Database.AddEntries(entries);
// Assert
count.Should().Be(3);
}
[Fact]
public void EntryExists_记录存在_返回True()
{
// Arrange
Database.InitializeDatabase();
var meta = CreateTestMeta();
Database.AddEntry(meta);
// Act
var exists = Database.EntryExists(meta.Md5, meta.Path);
// Assert
exists.Should().BeTrue();
}
[Fact]
public void EntryExists_记录不存在_返回False()
{
// Arrange
Database.InitializeDatabase();
// Act
var exists = Database.EntryExists("non_existent_md5", "/non/existent/path.wav");
// Assert
exists.Should().BeFalse();
}
[Fact]
public void AddEntry_重复UniqueId_第二次添加失败()
{
// Arrange
Database.InitializeDatabase();
var meta1 = CreateTestMeta();
var meta2 = CreateTestMeta();
meta2.UniqueId = meta1.UniqueId; // 使用相同的 UniqueId
Database.AddEntry(meta1);
// Act
var result = Database.AddEntry(meta2);
// Assert
result.Should().BeFalse();
}
static AudioFileMeta CreateTestMeta(string filename = "test.wav")
{
return new AudioFileMeta
{
Id = 0, // 自增 ID,由数据库生成
UniqueId = Guid.NewGuid().ToString("N"),
Md5 = Guid.NewGuid().ToString("N"),
Path = $"/test/path/{filename}",
Filename = filename,
Folder = "test",
Directory = "/test/path",
Duration = 10.5,
TotalSamples = 441000,
BitDepth = 24,
Channels = 2,
SampleRate = 44100,
Type = "WAV",
DateAdded = DateTime.Now,
OriginalModificationDate = DateTime.Now.AddDays(-1),
OriginationTime = DateTime.Now.AddDays(-1),
};
}
}