Как я могу использовать PrivateObject для доступа к закрытым членам как моего класса, так и его родителя?
Я тестирую класс, который является частью иерархии. Я настраивал свои тестовые классы с тестируемым объектом и PrivateObject
, чтобы разрешить доступ к этому объекту. Я получаю исключения, когда пытаюсь получить доступ к закрытым членам родительского класса.
Единственным обходным решением, которое я нашел до сих пор, является передача PrivateType
, указывающая базовый класс на конструктор PrivateObject
, но затем он не работает с частными членами подкласса.
Есть ли способ, которым я могу это сделать, возможно, используя параметр флаги привязки в методах Get * объекта Private?
Я попытался использовать автоматически созданные классы Accessor (щелкните правой кнопкой мыши в основном классе, Create Private Accessor). Тем не менее, это хуже: он показывает свойство, которое я могу прочитать, но он генерирует то же исключение, что и privateObject, и нет никаких других параметров, которые я могу использовать (флаги привязки или что-то еще), чтобы исправить исключение.
Вот мой примерный тестовый код. Я бы хотел, чтобы был какой-то способ построить и использовать PrivateObject для извлечения обоих полей.
public class BaseClass
{
private int one = 1;
}
public class SubClass : BaseClass
{
private int two = 2;
}
[TestClass]
public class UnitTest1
{
BindingFlags flags = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
[TestMethod]
public void TestMethod1()
{
SubClass test = new SubClass();
PrivateObject priv = new PrivateObject(test);
Assert.AreNotEqual<int>(0, (int)priv.GetFieldOrProperty("one", flags)); // System.MissingMethodException: Method 'PrivateObjectTester.SubClass.one' not found.
Assert.AreNotEqual<int>(0, (int)priv.GetFieldOrProperty("two", flags));
}
[TestMethod]
public void TestMethod2()
{
SubClass test = new SubClass();
PrivateObject priv = new PrivateObject(test, new PrivateType(typeof(BaseClass)));
Assert.AreNotEqual<int>(0, (int)priv.GetFieldOrProperty("one", flags));
Assert.AreNotEqual<int>(0, (int)priv.GetFieldOrProperty("two", flags)); // System.MissingMethodException: Method 'PrivateObjectTester.BaseClass.two' not found.
}
}
Ответы
Ответ 1
Я не нашел ответа, так что это то, что я делал. Я создал PrivateObjects
для каждого уровня иерархии классов, и мне просто нужно быть осторожным при написании тестовых примеров, что я использую правильный.
public class BaseClass
{
private int one = 1;
}
public class SubClass : BaseClass
{
private int two = 2;
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod()
{
SubClass test = new SubClass();
PrivateObject privSub = new PrivateObject(test, new PrivateType(typeof(SubClass)));
PrivateObject privBase = new PrivateObject(test, new PrivateType(typeof(BaseClass)));
Assert.AreNotEqual<int>(0, (int)privBase.GetFieldOrProperty("one"));
Assert.AreNotEqual<int>(0, (int)privSub.GetFieldOrProperty("two"));
}
}
Ответ 2
Вероятно, это не тот ответ, который вы хотите... но вы не должны тестировать оба класса в одном методе в первую очередь. Вы должны всегда тестировать только один класс за раз. Если вы чувствуете необходимость сделать это, я бы предположил, что ваш код нуждается в рефакторинге. Но, поскольку я не знаю вашу проблему с реальным кодом, я не могу сказать точно
Ответ 3
PrivateObject немного находится на "тупой" стороне, когда дело касается обработки наследования. К сожалению, его методы не являются виртуальными, поэтому нет простого способа изменить это поведение. У вас по существу есть два варианта: либо жить с ограничениями, либо создавать свой собственный помощник-помощник, который может обрабатывать унаследованные элементы прозрачно.
Ответ 4
// create an instance of class SearchPlanogramsBuilder:
SearchPlanogramsBuilder searchPlanogramBuilder = new SearchPlanogramsBuilder();
// executing the method BuildSearchParameters(return type is void) with input searchPlanoGramsFilters:
searchPlanogramBuilder.BuildSearchParameters(searchPlanoGramsFilters);
// create privateobject and pass instance created for the class:
PrivateObject helperobject1 = new PrivateObject(searchPlanogramBuilder);
// type cast exactly as parameter(which is private variable) in the method:
Collection<string> parameter = (Collection<string>)helperobject1.GetFieldOrProperty("parameters");
Ответ 5
Как писал Андре Пена. Почему вы хотели бы протестировать элементы private
базового класса через подкласс. У вас также не будет доступа к этим членам в обычном коде вашего подкласса. Вы должны сделать вкладкам Свойства protected
доступ к ним из подкласса.
Затем вы также можете протестировать этих членов с PrivateObject.
Ответ 6
Я хотел сделать то же самое, и я сделал эти методы расширения. Теперь он работает хорошо. Моя первоначальная идея - с вашего поста. Спасибо!
https://github.com/cactuaroid/PrivateObjectExtensions
В основном это поиск члена-владельца Type.GetFields()
и Type.GetProperties()
рекурсивно, а затем создание PrivateObject (или PrivateType) как правильный тип для доступа к члену.