diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a15f7417..466c2a9b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -282,6 +282,29 @@ jobs: cd Tests ../../tools/dotnet-stryker -f ../.github/stryker/Stryker.Config.Compression.json -v "${GITHUB_REF#refs/heads/}" -r "Dashboard" -r "cleartext" + benchmark: + name: Benchmarks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-dotnet@v3 + with: + dotnet-version: 8.0.x + - name: Run benchmark tests + run: cd Tests/Benchmarks/Testably.Abstractions.Benchmarks && dotnet run -c Release --framework net8.0 --exporters json --filter '*' + - name: Store benchmark results + uses: rhysd/github-action-benchmark@v1 + with: + name: Benchmarks + tool: 'benchmarkdotnet' + output-file-path: Tests/Benchmarks/Testably.Abstractions.Benchmarks/BenchmarkDotNet.Artifacts/results/Testably.Abstractions.Benchmarks.Benchmarks-report-full-compressed.json + github-token: ${{ secrets.GITHUB_TOKEN }} + benchmark-data-dir-path: '/docs/benchmarks' + auto-push: true + alert-threshold: '150%' + comment-on-alert: false + fail-on-alert: false + deploy: name: Deploy if: startsWith(github.ref, 'refs/heads/release/') diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 97c5fb95..f02ae397 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -295,3 +295,26 @@ jobs: -H "Authorization: token $GITHUB_TOKEN" \ -d "$body" fi + + benchmark: + name: Benchmarks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-dotnet@v3 + with: + dotnet-version: 8.0.x + - name: Run benchmark tests + run: cd Tests/Benchmarks/Testably.Abstractions.Benchmarks && dotnet run -c Release --framework net8.0 --exporters json --filter '*' + - name: Store benchmark results + uses: rhysd/github-action-benchmark@v1 + with: + name: Benchmarks + tool: 'benchmarkdotnet' + output-file-path: Tests/Benchmarks/Testably.Abstractions.Benchmarks/BenchmarkDotNet.Artifacts/results/Testably.Abstractions.Benchmarks.Benchmarks-report-full-compressed.json + github-token: ${{ secrets.GITHUB_TOKEN }} + auto-push: false + alert-threshold: '150%' + summary-always: true + comment-on-alert: true + fail-on-alert: true diff --git a/Directory.Packages.props b/Directory.Packages.props index 9fe602fc..b8b1aecd 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,6 +7,7 @@ + @@ -32,6 +33,7 @@ + diff --git a/Testably.Abstractions.sln b/Testably.Abstractions.sln index 6a4d696e..019ad34a 100644 --- a/Testably.Abstractions.sln +++ b/Testably.Abstractions.sln @@ -100,6 +100,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Testably.Abstractions.TestS EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Settings", "Settings", "{D32170F4-1455-4839-8EF4-9530F3AA642A}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Benchmarks", "Benchmarks", "{500E38FD-F587-4CC7-A7CE-10DA4AC76CE1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Testably.Abstractions.Benchmarks", "Tests\Benchmarks\Testably.Abstractions.Benchmarks\Testably.Abstractions.Benchmarks.csproj", "{459BB7E6-67C5-4C7B-99A8-09AD7D4CAE0C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -162,6 +166,10 @@ Global {241E6413-819C-4B06-A739-4D10C2A81365}.Debug|Any CPU.Build.0 = Debug|Any CPU {241E6413-819C-4B06-A739-4D10C2A81365}.Release|Any CPU.ActiveCfg = Release|Any CPU {241E6413-819C-4B06-A739-4D10C2A81365}.Release|Any CPU.Build.0 = Release|Any CPU + {459BB7E6-67C5-4C7B-99A8-09AD7D4CAE0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {459BB7E6-67C5-4C7B-99A8-09AD7D4CAE0C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {459BB7E6-67C5-4C7B-99A8-09AD7D4CAE0C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {459BB7E6-67C5-4C7B-99A8-09AD7D4CAE0C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -186,6 +194,8 @@ Global {0AEBB1A6-07D6-46DC-BC78-9771D380EBC0} = {2FDB2AAE-E5CE-483E-A1A6-EC0B0A4AD67B} {241E6413-819C-4B06-A739-4D10C2A81365} = {D32170F4-1455-4839-8EF4-9530F3AA642A} {D32170F4-1455-4839-8EF4-9530F3AA642A} = {61F335A6-9CE0-4040-A34F-E70B1A55077D} + {500E38FD-F587-4CC7-A7CE-10DA4AC76CE1} = {61F335A6-9CE0-4040-A34F-E70B1A55077D} + {459BB7E6-67C5-4C7B-99A8-09AD7D4CAE0C} = {500E38FD-F587-4CC7-A7CE-10DA4AC76CE1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {EC4D8481-B9FD-41B5-832A-369210993DF4} diff --git a/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Benchmarks.Constructor.cs b/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Benchmarks.Constructor.cs new file mode 100644 index 00000000..181cd6ec --- /dev/null +++ b/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Benchmarks.Constructor.cs @@ -0,0 +1,33 @@ +using BenchmarkDotNet.Attributes; +using System.Collections.Generic; +using System.Globalization; +using System.IO.Abstractions; +using System.Linq; +using Testably.Abstractions.Testing; +using Testably.Abstractions.Testing.Initializer; +using MockFileSystem = Testably.Abstractions.Testing.MockFileSystem; + +namespace Testably.Abstractions.Benchmarks; + +public partial class Benchmarks +{ + private readonly Dictionary _testData = CreateTestData(); + + [Benchmark] + public IFileSystem ConstructorEmpty_Testably() => new MockFileSystem(); + + [Benchmark] + public IFileSystem ConstructorWithInitialization_1000_Testably() => new MockFileSystem() + .Initialize() + .With(_testData.Select(x => new FileDescription(x.Key, x.Value)).ToArray()).FileSystem; + + private static Dictionary CreateTestData() + { + int filesCount = 1000; + int maxDirectoryDepth = 8; + return Enumerable.Range(0, filesCount) + .ToDictionary( + i => @$"C:\{string.Join(@"\", Enumerable.Range(0, (i % maxDirectoryDepth) + 1).Select(j => j.ToString(CultureInfo.InvariantCulture)))}\{i}.bin", + i => i.ToString(CultureInfo.InvariantCulture)); + } +} diff --git a/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Benchmarks.Usage.cs b/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Benchmarks.Usage.cs new file mode 100644 index 00000000..18210509 --- /dev/null +++ b/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Benchmarks.Usage.cs @@ -0,0 +1,22 @@ +using BenchmarkDotNet.Attributes; +using System.IO.Abstractions; +using MockFileSystem = Testably.Abstractions.Testing.MockFileSystem; + +namespace Testably.Abstractions.Benchmarks; + +public partial class Benchmarks +{ + private readonly string _directoryPath = @"C:\l1\l2\l3\l4\l5\l6\l7\l8\l9\l10"; + private readonly string _fileContent = "some file content"; + private readonly string _fileName = "filename.txt"; + + private readonly IFileSystem _fileSystem = new MockFileSystem(); + + [Benchmark] + public void CreateDirectory_Testably() + => _fileSystem.Directory.CreateDirectory(_directoryPath); + + [Benchmark] + public void WriteFile_Testably() + => _fileSystem.File.WriteAllText(_fileName, _fileContent); +} diff --git a/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Benchmarks.cs b/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Benchmarks.cs new file mode 100644 index 00000000..7c63df51 --- /dev/null +++ b/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Benchmarks.cs @@ -0,0 +1,9 @@ +using BenchmarkDotNet.Attributes; + +namespace Testably.Abstractions.Benchmarks; + +[RPlotExporter] +[MemoryDiagnoser] +public partial class Benchmarks +{ +} diff --git a/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Program.cs b/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Program.cs new file mode 100644 index 00000000..94780f0c --- /dev/null +++ b/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Program.cs @@ -0,0 +1,11 @@ +using BenchmarkDotNet.Running; + +namespace Testably.Abstractions.Benchmarks; + +internal static class Program +{ + public static void Main(string[] args) + { + BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); + } +} diff --git a/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Testably.Abstractions.Benchmarks.csproj b/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Testably.Abstractions.Benchmarks.csproj new file mode 100644 index 00000000..8daef84b --- /dev/null +++ b/Tests/Benchmarks/Testably.Abstractions.Benchmarks/Testably.Abstractions.Benchmarks.csproj @@ -0,0 +1,17 @@ + + + false + false + Exe + false + ..\..\..\Build\Tests\$(MSBuildProjectName) + net8.0 + $(NoWarn);MA0049 + + + + + + + +