使用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,导致类型初始化失败。
解决办法
- 静态Mock FilePickerFileType.Images:用Moq的
SetupStatic(需要Moq 4.16+)来Mock这个静态属性,避免触发未实现代码:
// 在测试类构造函数或测试方法开头添加 Mock.SetupStatic(() => FilePickerFileType.Images) .Returns(new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>()));
- Mock PickMultiplesAsync返回值:确保调用该方法时返回预期结果(比如空集合,避免后续遍历出错):
// 在测试方法或构造函数中添加 _pickerService.Setup(x => x.PickMultiplesAsync(It.IsAny<PickOptions>())) .ReturnsAsync(Enumerable.Empty<FileResult>());
- 避免测试中实例化UI弹窗:
OpenPopup里直接实例化TooManyImagesPopup可能导致测试问题,建议Mock导航服务的PushPopup方法:
// 导航服务Mock设置 _navigationServiceMock.Setup(x => x.PushPopup(It.IsAny<TooManyImagesPopup>())) .Returns(Task.CompletedTask);
内容的提问来源于stack exchange,提问作者WoistdasNiveau
相关产品推荐
相关产品推荐

