From 865797d3f88b42953a126a5352e7a61312bea8be Mon Sep 17 00:00:00 2001 From: "a.beging@eas-solutions.de" Date: Thu, 30 Apr 2026 10:33:35 +0200 Subject: [PATCH] Add unit tests for LocalStorageService: implement tests for GetItem, SetItem, and RemoveItem methods --- .../FoodsharingSiegen.Tests.csproj | 26 ++++++ .../LocalStorageServiceTests.cs | 87 +++++++++++++++++++ FoodsharingSiegen.sln | 45 ++++++++++ 3 files changed, 158 insertions(+) create mode 100644 FoodsharingSiegen.Tests/FoodsharingSiegen.Tests.csproj create mode 100644 FoodsharingSiegen.Tests/LocalStorageServiceTests.cs diff --git a/FoodsharingSiegen.Tests/FoodsharingSiegen.Tests.csproj b/FoodsharingSiegen.Tests/FoodsharingSiegen.Tests.csproj new file mode 100644 index 0000000..8ac016c --- /dev/null +++ b/FoodsharingSiegen.Tests/FoodsharingSiegen.Tests.csproj @@ -0,0 +1,26 @@ + + + + net10.0 + enable + enable + false + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FoodsharingSiegen.Tests/LocalStorageServiceTests.cs b/FoodsharingSiegen.Tests/LocalStorageServiceTests.cs new file mode 100644 index 0000000..ba60df3 --- /dev/null +++ b/FoodsharingSiegen.Tests/LocalStorageServiceTests.cs @@ -0,0 +1,87 @@ +using System.Text.Json; +using FoodsharingSiegen.Server.Service; +using Microsoft.JSInterop; +using Moq; +using Xunit; + +namespace FoodsharingSiegen.Tests +{ + public class LocalStorageServiceTests + { + [Fact] + public async Task GetItem_ReturnsDeserializedObject_WhenItemExists() + { + // Arrange + var mockJsRuntime = new Mock(); + var service = new LocalStorageService(mockJsRuntime.Object); + var expectedObject = new { Name = "Test" }; + var jsonString = JsonSerializer.Serialize(expectedObject); + + mockJsRuntime.Setup(x => x.InvokeAsync("localStorage.getItem", It.IsAny())) + .ReturnsAsync(jsonString); + + // Act + var result = await service.GetItem("testKey"); + + // Assert + Assert.NotNull(result); + mockJsRuntime.Verify(x => x.InvokeAsync("localStorage.getItem", It.Is(args => args.Length == 1 && args[0].ToString() == "testKey")), Times.Once); + } + + [Fact] + public async Task GetItem_ReturnsDefault_WhenItemDoesNotExist() + { + // Arrange + var mockJsRuntime = new Mock(); + var service = new LocalStorageService(mockJsRuntime.Object); + + mockJsRuntime.Setup(x => x.InvokeAsync("localStorage.getItem", It.IsAny())) + .ReturnsAsync((string?)null); + + // Act + var result = await service.GetItem("testKey"); + + // Assert + Assert.Null(result); + } + + [Fact] + public async Task SetItem_CallsSetItemInLocalStorage() + { + // Arrange + var mockJsRuntime = new Mock(); + var service = new LocalStorageService(mockJsRuntime.Object); + var objectToSave = new { Name = "Test" }; + var expectedJson = JsonSerializer.Serialize(objectToSave); + + // Act + await service.SetItem("testKey", objectToSave); + + // Assert + // Note: InvokeVoidAsync is an extension method that calls InvokeAsync under the hood in Blazor. + mockJsRuntime.Verify( + x => x.InvokeAsync( + "localStorage.setItem", + It.Is(args => args.Length == 2 && args[0].ToString() == "testKey" && args[1].ToString() == expectedJson)), + Times.Once); + } + + [Fact] + public async Task RemoveItem_CallsRemoveItemInLocalStorage() + { + // Arrange + var mockJsRuntime = new Mock(); + var service = new LocalStorageService(mockJsRuntime.Object); + + // Act + await service.RemoveItem("testKey"); + + // Assert + mockJsRuntime.Verify( + x => x.InvokeAsync( + "localStorage.removeItem", + It.Is(args => args.Length == 1 && args[0].ToString() == "testKey")), + Times.Once); + } + } +} \ No newline at end of file diff --git a/FoodsharingSiegen.sln b/FoodsharingSiegen.sln index 8e33901..0e618ea 100644 --- a/FoodsharingSiegen.sln +++ b/FoodsharingSiegen.sln @@ -6,23 +6,68 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoodsharingSiegen.Contracts EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoodsharingSiegen.Shared", "FoodsharingSiegen.Shared\FoodsharingSiegen.Shared.csproj", "{625167D9-A375-40AF-82DE-87484519F6D9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoodsharingSiegen.Tests", "FoodsharingSiegen.Tests\FoodsharingSiegen.Tests.csproj", "{A3BBF859-E3BB-420A-895F-B1BCF4B38B74}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {63D6CC91-095D-44C3-8752-660DDF9C710C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {63D6CC91-095D-44C3-8752-660DDF9C710C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {63D6CC91-095D-44C3-8752-660DDF9C710C}.Debug|x64.ActiveCfg = Debug|Any CPU + {63D6CC91-095D-44C3-8752-660DDF9C710C}.Debug|x64.Build.0 = Debug|Any CPU + {63D6CC91-095D-44C3-8752-660DDF9C710C}.Debug|x86.ActiveCfg = Debug|Any CPU + {63D6CC91-095D-44C3-8752-660DDF9C710C}.Debug|x86.Build.0 = Debug|Any CPU {63D6CC91-095D-44C3-8752-660DDF9C710C}.Release|Any CPU.ActiveCfg = Release|Any CPU {63D6CC91-095D-44C3-8752-660DDF9C710C}.Release|Any CPU.Build.0 = Release|Any CPU + {63D6CC91-095D-44C3-8752-660DDF9C710C}.Release|x64.ActiveCfg = Release|Any CPU + {63D6CC91-095D-44C3-8752-660DDF9C710C}.Release|x64.Build.0 = Release|Any CPU + {63D6CC91-095D-44C3-8752-660DDF9C710C}.Release|x86.ActiveCfg = Release|Any CPU + {63D6CC91-095D-44C3-8752-660DDF9C710C}.Release|x86.Build.0 = Release|Any CPU {F39AE3B4-E4CE-421E-AFB0-E9C9B3B670FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F39AE3B4-E4CE-421E-AFB0-E9C9B3B670FE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F39AE3B4-E4CE-421E-AFB0-E9C9B3B670FE}.Debug|x64.ActiveCfg = Debug|Any CPU + {F39AE3B4-E4CE-421E-AFB0-E9C9B3B670FE}.Debug|x64.Build.0 = Debug|Any CPU + {F39AE3B4-E4CE-421E-AFB0-E9C9B3B670FE}.Debug|x86.ActiveCfg = Debug|Any CPU + {F39AE3B4-E4CE-421E-AFB0-E9C9B3B670FE}.Debug|x86.Build.0 = Debug|Any CPU {F39AE3B4-E4CE-421E-AFB0-E9C9B3B670FE}.Release|Any CPU.ActiveCfg = Release|Any CPU {F39AE3B4-E4CE-421E-AFB0-E9C9B3B670FE}.Release|Any CPU.Build.0 = Release|Any CPU + {F39AE3B4-E4CE-421E-AFB0-E9C9B3B670FE}.Release|x64.ActiveCfg = Release|Any CPU + {F39AE3B4-E4CE-421E-AFB0-E9C9B3B670FE}.Release|x64.Build.0 = Release|Any CPU + {F39AE3B4-E4CE-421E-AFB0-E9C9B3B670FE}.Release|x86.ActiveCfg = Release|Any CPU + {F39AE3B4-E4CE-421E-AFB0-E9C9B3B670FE}.Release|x86.Build.0 = Release|Any CPU {625167D9-A375-40AF-82DE-87484519F6D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {625167D9-A375-40AF-82DE-87484519F6D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {625167D9-A375-40AF-82DE-87484519F6D9}.Debug|x64.ActiveCfg = Debug|Any CPU + {625167D9-A375-40AF-82DE-87484519F6D9}.Debug|x64.Build.0 = Debug|Any CPU + {625167D9-A375-40AF-82DE-87484519F6D9}.Debug|x86.ActiveCfg = Debug|Any CPU + {625167D9-A375-40AF-82DE-87484519F6D9}.Debug|x86.Build.0 = Debug|Any CPU {625167D9-A375-40AF-82DE-87484519F6D9}.Release|Any CPU.ActiveCfg = Release|Any CPU {625167D9-A375-40AF-82DE-87484519F6D9}.Release|Any CPU.Build.0 = Release|Any CPU + {625167D9-A375-40AF-82DE-87484519F6D9}.Release|x64.ActiveCfg = Release|Any CPU + {625167D9-A375-40AF-82DE-87484519F6D9}.Release|x64.Build.0 = Release|Any CPU + {625167D9-A375-40AF-82DE-87484519F6D9}.Release|x86.ActiveCfg = Release|Any CPU + {625167D9-A375-40AF-82DE-87484519F6D9}.Release|x86.Build.0 = Release|Any CPU + {A3BBF859-E3BB-420A-895F-B1BCF4B38B74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A3BBF859-E3BB-420A-895F-B1BCF4B38B74}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A3BBF859-E3BB-420A-895F-B1BCF4B38B74}.Debug|x64.ActiveCfg = Debug|Any CPU + {A3BBF859-E3BB-420A-895F-B1BCF4B38B74}.Debug|x64.Build.0 = Debug|Any CPU + {A3BBF859-E3BB-420A-895F-B1BCF4B38B74}.Debug|x86.ActiveCfg = Debug|Any CPU + {A3BBF859-E3BB-420A-895F-B1BCF4B38B74}.Debug|x86.Build.0 = Debug|Any CPU + {A3BBF859-E3BB-420A-895F-B1BCF4B38B74}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A3BBF859-E3BB-420A-895F-B1BCF4B38B74}.Release|Any CPU.Build.0 = Release|Any CPU + {A3BBF859-E3BB-420A-895F-B1BCF4B38B74}.Release|x64.ActiveCfg = Release|Any CPU + {A3BBF859-E3BB-420A-895F-B1BCF4B38B74}.Release|x64.Build.0 = Release|Any CPU + {A3BBF859-E3BB-420A-895F-B1BCF4B38B74}.Release|x86.ActiveCfg = Release|Any CPU + {A3BBF859-E3BB-420A-895F-B1BCF4B38B74}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection EndGlobal