Вот почему статика проблематична.
Вы можете абстрагировать функциональность интерфейса и создать реализацию по умолчанию, которая использует статический метод. Затем вы можете использовать внедрение зависимостей, что делает этот модульный тест тривиальным - смоделируйте зависимость от IVisualTreeHelper или откатите свою собственную реализацию-заглушку, которую вы можете настроить для возврата любого назначенного вами значения.
public class Foo
{
static IVisualTreeHelper visualTreeHelper;
static Foo()
{
Foo.visualTreeHelper = new FrameworkVisualTreeHelper();
}
public Foo(IVisualTreeHelper visualTreeHelper)
{
Foo.visualTreeHelper = visualTreeHelper;
}
public static DependencyObject GetParentObject(DependencyObject child)
{
if (child == null) return null;
ContentElement contentElement = child as ContentElement;
if (contentElement != null)
{
var parent = ContentOperations.GetParent(contentElement);
if (parent != null) return parent;
var fce = contentElement as FrameworkContentElement;
return fce != null ? fce.Parent : null;
}
//if it's not a ContentElement, rely on the IVisualTreeHelper
return visualTreeHelper.GetParent(child);
}
}
public interface IVisualTreeHelper
{
DependencyObject GetParent(DependencyObject reference);
}
public class FrameworkVisualTreeHelper : IVisualTreeHelper
{
public DependencyObject GetParent(DependencyObject reference)
{
return VisualTreeHelper.GetParent(reference);
}
}
Очевидно, что вам может потребоваться добавить другие методы VisualTreeHelper
в ваш интерфейс и реализацию по умолчанию, если вы используете другие методы в других местах.
Это все еще не совсем чисто, потому что тестируемый модуль сам по себе является статическим, и вы столкнетесь с точно такой же проблемой, когда попытаетесь выполнить модульное тестирование любого класса, который использует статические методы вашего класса UIHelper.