我有以下问题,我想测试 WPF 中的 ValidationRule 是否按预期工作。 我的 ValidationRule 使用 BindingExpression 中定义的 DataItem 中的一些数据。
调用 Validate 函数不是问题,但我没有计划如何为 BindingExpression 参数设置模拟。 我尝试使用 Moq 创建一个模拟,但它是一个密封类,因此这是不可能的。 我尝试使用构造函数创建一个实例,但构造函数是内部的,因此这也是不可能的。
有什么解决方案可以设置 BindingExpression,也可以在内部提供一些数据进行测试吗?
如果您无法模拟参数,您始终可以引入一个接受未包装数据的中间方法。继承的 API 必须委托给这个新的中间 API。您还可以将数据转换为新类型,而不是解包它。
以下示例展示了如何将数据转换为可模拟对象,以便您可以正确测试行为:
示例ValidationRule.cs
class ExampleValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo, BindingExpressionBase owner)
{
// Store the required information in the BindingInfo.
// Consider using a constructor over the initializer for more convenience.
var bindingInfo = new BindingInfo()
{
Source = ((BindingExpression)owner).ResolvedSource
};
// And delegate to a custom API
return Validate(value, cultureInfo, bindingInfo);
}
// Use this method to test the Validate override. Here you can mock the BindingInfo if required.
// From an internal point of view or design perspective,
// this method is the true entry point of the validation logic.
// The inherited base methods are only!!! used to delegate the parameters to this method.
// This allows to ignore the inherited Validate methods in your unit test
// as they contain no functionality.
public ValidationResult Validate(object value, CultureInfo cultureInfo, BindingInfo owner)
{
// TODO::Implemet the validation here
}
}
BindingInfo.cs
包含
BindingExpression
相关信息的可模拟类。
考虑在应用程序代码中使用构造函数以更加方便,但使用重载以避免测试代码中的
BindingExpressionBase
或对象初始值设定项。
class BindingInfo
{
public object Source { get; init set; }
public BindingInfo(BindingExpressionBase bindingExpressionBase)
{
// For the sake of an example
this.Source = bindingExpressionBase is BindingExpression bindingExpression
? bindingExpression.ResolvedSource
: null;
}
}