Avalonia怎么在单元测试中测试ViewModel Avalonia单元测试教程

来源:这里教程网 时间:2026-02-21 17:37:37 作者:

在 Avalonia 中对 ViewModel 做单元测试,核心思路是:把 ViewModel 当作普通 C# 类来测,不依赖 UI、不启动窗口、不触发渲染。只要它实现了

INotifyPropertyChanged
、用了命令(
ICommand
)、有业务逻辑或状态流转,就能独立验证。

ViewModel 必须可测试的前提

确保你的 ViewModel 基类已正确支持属性变更通知和命令机制:

继承自
ReactiveUI.ViewModel
CommunityToolkit.Mvvm.ObservableObject
,或手动实现
INotifyPropertyChanged
使用
RelayCommand
/
ReactiveCommand
/
AsyncRelayCommand
定义命令,而非直接写事件处理方法
避免在 ViewModel 中调用
Application.Current
Dispatcher.UIThread
DialogHost
等 Avalonia UI 特定对象
依赖的服务(如数据访问、网络请求)应通过接口注入,方便在测试中用 Moq 或 Fake 替换

写一个基础单元测试(以 CommunityToolkit.Mvvm 为例)

假设你有如下 ViewModel:

public partial class LoginViewModel : ObservableObject
{
    [ObservableProperty]
    private string _account;
<pre class="brush:php;toolbar:false;">[ObservableProperty]
private string _pwd;
[ICommand]
public void Login()
{
    if (!string.IsNullOrWhiteSpace(Account) && Account.Length > 2)
        IsLoggedIn = true;
}
[ObservableProperty]
private bool _isLoggedIn;

}

对应测试代码(用 xUnit + Moq):

新建 xUnit 测试项目,引用被测项目和
CommunityToolkit.Mvvm
创建测试类,实例化 ViewModel 验证属性赋值后是否触发通知 调用命令后检查状态变化

示例:

[Fact]
public void Login_WhenAccountValid_SetsIsLoggedInToTrue()
{
    var vm = new LoginViewModel();
    vm.Account = "admin";
    vm.Pwd = "123";
<pre class="brush:php;toolbar:false;">vm.Login();
Assert.True(vm.IsLoggedIn);

}

测试属性变更通知(INPC)

关键是要验证

PropertyChanged
事件是否被正确触发:

订阅
PropertyChanged
事件,记录触发的属性名
修改属性,检查是否收到对应事件 推荐用
CommunityToolkit.Mvvm
SetProperty
[ObservableProperty]
,它们默认保障通知逻辑正确

简单验证方式:

var vm = new LoginViewModel();
string? raisedProp = null;
vm.PropertyChanged += (_, e) => raisedProp = e.PropertyName;
<p>vm.Account = "test";
Assert.Equal("Account", raisedProp);</p>

测试异步命令和响应式逻辑

如果用了 ReactiveUI,重点测

ReactiveCommand
的执行、CanExecute 变化、执行结果:

TestScheduler
控制时间流(适合复杂响应式链)
Execute
调用后,断言输出属性、服务调用次数、异常等
模拟依赖服务返回 Task 或 Observable,例如用
Observable.Return(...)
Task.FromResult(...)

例如测试登录失败场景:

var mockAuthService = new Mock<IAuthService>();
mockAuthService.Setup(x => x.LoginAsync(It.IsAny<string>(), It.IsAny<string>()))
               .ReturnsAsync(false);
<p>var vm = new LoginViewModel(mockAuthService.Object);
vm.Account = "bad";
vm.Pwd = "pass";
await vm.LoginCommand.ExecuteAsync(null);</p><p>Assert.False(vm.IsLoggedIn);</p>

基本上就这些。不复杂但容易忽略的是:别在 ViewModel 里做 UI 导航、弹窗、资源加载——那些该交给 View 或专门的导航服务,否则测试会卡住或失败。

相关推荐