test: add app-level smoke baselines and mobile CI test jobs
Co-authored-by: Velik <hongochai10@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>AppClientBase.UnitTests</AssemblyName>
|
||||
<RootNamespace>AppClientBase.UnitTests</RootNamespace>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- EN: Test framework dependencies / VI: Phụ thuộc framework test -->
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||
<PackageReference Include="xunit" Version="2.9.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="6.12.2" />
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.2">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
|
||||
<!-- EN: Source generator package used by included view models.
|
||||
VI: Gói source generator dùng cho view model được include. -->
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- EN: Reuse app source files that are platform-neutral.
|
||||
VI: Tái sử dụng source file ứng dụng không phụ thuộc nền tảng. -->
|
||||
<Compile Include="..\..\ViewModels\BaseViewModel.cs" Link="ViewModels\BaseViewModel.cs" />
|
||||
<Compile Include="..\..\ViewModels\MainViewModel.cs" Link="ViewModels\MainViewModel.cs" />
|
||||
<Compile Include="..\..\Services\INavigationService.cs" Link="Services\INavigationService.cs" />
|
||||
<Compile Include="..\..\Services\ISettingsService.cs" Link="Services\ISettingsService.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,81 @@
|
||||
using AppClientBase.Services;
|
||||
using AppClientBase.ViewModels;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace AppClientBase.UnitTests.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Unit tests for main view model behavior.
|
||||
/// VI: Unit tests cho hành vi của main view model.
|
||||
/// </summary>
|
||||
public class MainViewModelTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_ShouldSetDefaultTitleAndWelcomeMessage()
|
||||
{
|
||||
// Arrange
|
||||
var navigationService = new FakeNavigationService();
|
||||
var settingsService = new FakeSettingsService();
|
||||
|
||||
// Act
|
||||
var viewModel = new MainViewModel(navigationService, settingsService);
|
||||
|
||||
// Assert
|
||||
viewModel.Title.Should().Be("Home");
|
||||
viewModel.WelcomeMessage.Should().Be("Welcome to AppClientBase!");
|
||||
viewModel.ClickCount.Should().Be(0);
|
||||
viewModel.ButtonText.Should().Be("Click me");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IncrementCounterCommand_ShouldIncreaseCountAndPersistSetting()
|
||||
{
|
||||
// Arrange
|
||||
var navigationService = new FakeNavigationService();
|
||||
var settingsService = new FakeSettingsService();
|
||||
var viewModel = new MainViewModel(navigationService, settingsService);
|
||||
|
||||
// Act
|
||||
viewModel.IncrementCounterCommand.Execute(null);
|
||||
viewModel.IncrementCounterCommand.Execute(null);
|
||||
|
||||
// Assert
|
||||
viewModel.ClickCount.Should().Be(2);
|
||||
viewModel.ButtonText.Should().Be("Clicked 2 times");
|
||||
settingsService.Get("ClickCount", 0).Should().Be(2);
|
||||
}
|
||||
|
||||
private sealed class FakeNavigationService : INavigationService
|
||||
{
|
||||
public Task GoToAsync(string route, IDictionary<string, object>? parameters = null) => Task.CompletedTask;
|
||||
|
||||
public Task GoBackAsync() => Task.CompletedTask;
|
||||
}
|
||||
|
||||
private sealed class FakeSettingsService : ISettingsService
|
||||
{
|
||||
private readonly Dictionary<string, object?> _store = new(StringComparer.Ordinal);
|
||||
|
||||
public T Get<T>(string key, T defaultValue)
|
||||
{
|
||||
if (_store.TryGetValue(key, out var value) && value is T typed)
|
||||
{
|
||||
return typed;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public void Set<T>(string key, T value)
|
||||
{
|
||||
_store[key] = value;
|
||||
}
|
||||
|
||||
public bool Contains(string key) => _store.ContainsKey(key);
|
||||
|
||||
public void Remove(string key) => _store.Remove(key);
|
||||
|
||||
public void Clear() => _store.Clear();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user