【问题标题】:How can I test methods containing Application.Current如何测试包含 Application.Current 的方法
【发布时间】:2019-11-12 02:54:49
【问题描述】:

很少有方法具有 Application.Current.Properties 和 Application.Current.SavePropertiesAsync 方法。

那么我如何测试包含这两个的方法呢?在尝试为他们使用 Unity 容器后我被卡住了,但它只适用于属性而不是 SavePropertiesAsync

我该如何实现它?

我已将其实现为:

public interface IAppProperties { IDictionary<string, object> Properties { get; set; } }

public class AppProperty:IAppProperties
{
    public const string AppPropertiesName = "AppProperties";

    public IDictionary<string, object> Properties { get; set; }

    public AppProperty(IDictionary<string, object> appProperties)
    {
        Properties = appProperties;
    }
}

在应用 XAML.cs 中

UnityContainer container = new UnityContainer(); 
if (!IsUnitTestCase) 
{ 
    container.RegisterInstance<IDictionary<string, object>>(AppProperty.AppPropertiesName, Application.Current.Properties); 
} 
else 
{ 
    container.RegisterInstance<IDictionary<string, object>>(AppProperty.AppPropertiesName, new Dictionary<string,object>()); 
} 
container.RegisterType<IAppProperties,AppProperty>();
Application.Current.Resources.Add("Unity", container);

【问题讨论】:

  • 您需要存根Application 对象。看看What is a Stub。如果您需要更多帮助,请使用您尝试过的测试代码更新问题

标签: c# unit-testing mvvm xamarin.forms


【解决方案1】:

如果一个类直接依赖于Application.Current,那么你不能测试它。但看起来你已经在依赖抽象的轨道上。

假设你需要做三件事:

  • 检索属性
  • 设置属性
  • 保存所有属性

您可以定义代表这些行为的抽象:

public interface IApplicationProperties
{
    object GetProperty(string key);
    void SetProperty(string key, object value);
    Task SavePropertiesAsync();
}

您的默认实现可能如下所示(尽管还有很大的改进空间。)

public class ApplicationProperties : IApplicationProperties
{
    private readonly Application _application;

    public ApplicationProperties(Application application)
    {
        _application = application;
    }

    public object GetProperty(string key)
    {
        // or whatever behavior you want when the key is missing
        return _application.Properties.TryGetValue(key, out object result) ? result : null;
    }

    public void SetProperty(string key, object value)
    {
        _application.Properties[key] = value;
    }

    public async Task SavePropertiesAsync()
    {
        await _application.SavePropertiesAsync();
    }
}

这个类可以依赖于Application.Current,也可以将Application注入其中。

这可能受益于更好的类型检查,或许还可以限制/定义可以读取和设置的设置。但它允许您通过抽象访问Application 的行为,同时模拟单元测试的抽象。您可以使用 Moq 或编写一个简单的测试替身以在测试中使用。

以下是对包含测试替身的方法的调整:

// base class
public abstract class ApplicationPropertiesBase : IApplicationProperties
{
    protected abstract IDictionary<string, object> Properties { get; }

    public object GetProperty(string key)
    {
        return Properties.TryGetValue(key, out object result) ? result : null;
    }

    public void SetProperty(string key, object value)
    {
        Properties[key] = value;
    }

    public abstract Task SavePropertiesAsync();
}

// inject this
public class ApplicationProperties : ApplicationPropertiesBase
{
    private readonly Application _application;

    public ApplicationProperties(Application application)
    {
        _application = application;
    }

    protected override IDictionary<string, object> Properties => _application.Properties;

    public override async Task SavePropertiesAsync()
    {
        await _application.SavePropertiesAsync();
    }
}

// use for tests 
public class ApplicationPropertiesTestDouble : ApplicationPropertiesBase
{
    private readonly IDictionary<string, object> properties = 
        new Dictionary<string, object>();

    protected override IDictionary<string, object> Properties => properties;

    public override async Task SavePropertiesAsync()
    { }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-29
    • 2020-09-25
    • 2023-03-19
    • 1970-01-01
    • 2022-06-23
    • 1970-01-01
    相关资源
    最近更新 更多