You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用xUnit测试含FilePicker的ViewModel时遇初始化异常

问题:测试UploadMore方法时抛出FilePickerFileType初始化异常

我要测试CutImagesViewModel里的UploadMore方法对ImagesCountBelow10布尔值的设置逻辑。已经创建了PickerService的Mock并注入到ViewModel实例里,但运行测试时还是抛出了异常:

System.TypeInitializationException : The type initializer for 'Microsoft.Maui.Storage.FilePickerFileType' threw an exception.
---- Microsoft.Maui.ApplicationModel.NotImplementedInReferenceAssemblyException : This functionality is not implemented in the portable version of this assembly. You should reference the NuGet package from your main application project in order to reference the platform-specific implementation.

我原以为Mock会直接返回空IEnumerable,不会触发FilePicker的实际调用,但实际并非如此,谷歌搜了也没找到有效解决办法,搞不懂哪里出问题。

待测试方法

[RelayCommand]
public async Task UploadMore() {
  IEnumerable<FileResult> result = await _pickerService.PickMultiplesAsync(new PickOptions {
    PickerTitle = "Choose Images",
    FileTypes = FilePickerFileType.Images
  });
  await Task.Delay(250);
  foreach(FileResult file in result) {
    Stream up = await file.OpenReadAsync();
    Guid id;
    using(MemoryStream stream = new MemoryStream()) {
      up.CopyTo(stream);
      CropImageModel model = new CropImageModel(stream.ToArray());
      UploadImages.Add(model);
      croppedImages.Add(model);
      model.Index = croppedImages.Count;
    }
  }
  if (UploadImages.Count > 10) {
    await OpenPopup();
  }
}

[RelayCommand]
public async Task OpenPopup() {
  ImagesCountBelow10 = false;
  DeleteBool = true;
  TooManyImagesPopup pop = new TooManyImagesPopup() {
    BindingContext = this
  };
  await NavigationService.PushPopup(pop);
}

测试方法

private readonly CutImagesViewModel _cutImagesViewModel;
public CutImagesViewModelTests() {
  _cutImagesViewModel = new CutImagesViewModel(_navigationServiceMock.Object, _pickerService.Object) {
    UploadImages = new ObservableCollection<CropImageModel>()
  };
}

[Fact]
public async void UploadMore_ImagesCount11ShouldOpenPupup() {
  for (int i = 0; i < 12; i++) {
    _cutImagesViewModel.UploadImages.Add(new MauiDoggoApp.Models.CropImageModel(new byte[1] {
      (byte) i
    }));
  }

  await _cutImagesViewModel.UploadMoreCommand.ExecuteAsync(null);

  Assert.False(_cutImagesViewModel.ImagesCountBelow10);
}

基础测试类

public class BaseViewModelTests {
  protected readonly Mock<INavigationService> _navigationServiceMock;
  protected readonly Mock<IPickerService> _pickerService;

  public BaseViewModelTests() {
    _navigationServiceMock = new Mock<INavigationService>();
    _pickerService = new Mock<IPickerService>();
  }
}

问题原因

异常不是来自Mock的调用,而是在创建PickOptions实例时,访问了FilePickerFileType.Images这个静态属性——这个属性在MAUI的引用程序集中没有实现,会直接抛出NotImplementedInReferenceAssemblyException,导致类型初始化失败。

解决办法

  1. 静态Mock FilePickerFileType.Images:用Moq的SetupStatic(需要Moq 4.16+)来Mock这个静态属性,避免触发未实现代码:
// 在测试类构造函数或测试方法开头添加
Mock.SetupStatic(() => FilePickerFileType.Images)
    .Returns(new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>()));
  1. Mock PickMultiplesAsync返回值:确保调用该方法时返回预期结果(比如空集合,避免后续遍历出错):
// 在测试方法或构造函数中添加
_pickerService.Setup(x => x.PickMultiplesAsync(It.IsAny<PickOptions>()))
              .ReturnsAsync(Enumerable.Empty<FileResult>());
  1. 避免测试中实例化UI弹窗:OpenPopup里直接实例化TooManyImagesPopup可能导致测试问题,建议Mock导航服务的PushPopup方法:
// 导航服务Mock设置
_navigationServiceMock.Setup(x => x.PushPopup(It.IsAny<TooManyImagesPopup>()))
                      .Returns(Task.CompletedTask);

内容的提问来源于stack exchange,提问作者WoistdasNiveau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 04:35:25