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

如何在Xamarin.Forms中单元测试Preferences存储值

异常根因

抛出Xamarin.Essentials.NotImplementedInReferenceAssemblyException是因为单元测试项目默认引用的Xamarin.Essentials是仅包含API签名的引用程序集,没有对应Android、iOS、Windows等平台的原生存储实现,脱离平台宿主环境直接调用Preferences静态类的方法必然触发该异常。
另外你代码里写的Assert.Equals是常见误用:这个方法是根类Object的静态方法,不是单元测试框架提供的断言方法,即使存储逻辑正常,也无法达到预期的断言效果,应该用测试框架(xUnit/NUnit/MSTest)提供的Assert.Equal做值比较。

可行测试方案

方案1:使用官方内置测试实现(无需改动业务代码)

Xamarin.Essentials从1.6版本开始内置了专门给单元测试用的内存存储实现,不需要依赖平台环境,只需要在测试初始化阶段注入即可:

  • 确保单元测试项目安装的Xamarin.Essentials包版本和业务项目一致
  • 在测试类初始化逻辑中注入内存实现,之后就可以按正常逻辑调用Preferences API:
using Xamarin.Essentials;
using Xunit;

public class PreferenceTests
{
    public PreferenceTests()
    {
        // 注入测试专用内存版实现,数据仅在测试运行时存在于内存
        Preferences.SetImplementation(Preferences.InMemoryImplementation);
    }

    [Fact]
    public void AppVersion_AfterSet_ReturnsCorrectValue()
    {
        // 执行存储逻辑
        Preferences.Set("AppVersion", "1.0");
        // 校验结果
        var storedVersion = Preferences.Get("AppVersion", string.Empty);
        Assert.Equal("1.0", storedVersion);
    }
}

该实现不会产生持久化脏数据,每个测试类初始化时会重置存储状态,适合不想改动现有业务代码的场景。

方案2:抽象依赖封装(推荐,符合单元测试隔离原则)

静态类天生是强耦合的,不利于单元测试隔离,架构规范的项目建议对Preferences做接口抽象,业务代码依赖抽象而非具体静态实现:

  • 定义存储抽象接口,以及对应Xamarin.Essentials的生产环境实现:
public interface IAppPreferences
{
    void Set<T>(string key, T value);
    T Get<T>(string key, T defaultValue);
}

public class EssentialsAppPreferences : IAppPreferences
{
    public T Get<T>(string key, T defaultValue) => Preferences.Get(key, defaultValue);
    public void Set<T>(string key, T value) => Preferences.Set(key, value);
}
  • 业务代码通过依赖注入获取IAppPreferences实例操作,不要直接调用静态Preferences类:
public class AppConfigService
{
    private readonly IAppPreferences _preferences;
    public AppConfigService(IAppPreferences preferences)
    {
        _preferences = preferences;
    }

    public void SaveCurrentAppVersion()
    {
        _preferences.Set("AppVersion", "1.0");
    }
}
  • 单元测试时不需要依赖Xamarin.Essentials的任何实现,自己写简单的内存版存储即可完成校验:
// 测试专用内存实现
public class InMemoryTestPreferences : IAppPreferences
{
    private readonly Dictionary<string, object> _tempStorage = new();
    public T Get<T>(string key, T defaultValue) 
        => _tempStorage.TryGetValue(key, out var val) ? (T)val : defaultValue;
    public void Set<T>(string key, T value) => _tempStorage[key] = value;
}

// 测试用例
[Fact]
public void SaveCurrentAppVersion_WhenCalled_StoreVersionCorrectly()
{
    var testPrefs = new InMemoryTestPreferences();
    var configService = new AppConfigService(testPrefs);
    
    configService.SaveCurrentAppVersion();
    
    Assert.Equal("1.0", testPrefs.Get("AppVersion", string.Empty));
}

该方案完全不依赖Xamarin.Essentials的内部实现,测试运行速度更快,也不会因为第三方库版本变动导致测试失败,是长期维护项目的首选方案。如果你用的Xamarin.Essentials版本低于1.6没有内置测试实现,只能用该方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 10:36:22