Как заполнить случайный объект случайными данными во время выполнения - PullRequest
0 голосов
/ 08 апреля 2020

Я хочу создать небольшой инструмент тестирования для моей программы, который заполняет все свойства случайного объекта (неизвестный тип во время компиляции). Пример структуры:

    public class HeadObject
    {
        public Company Company { get; set; }
        public CompanyAddress CompanyAddress { get; set; }
        public List<Details> Details{ get; set; }
        public ApplicationUser AppUser { get; set; }
    }

и, например, класс Company будет выглядеть следующим образом:

    public class Company
   {
        public string CompanyName{ get; set; }
        public string PhoneNumber{ get; set; }
        public Address Adress{ get; set; }
        public int CompanyNo{ get; set; }
        public List<Employee> Employees{ get; set; }
   }

это довольно упрощенно, потому что в каждом HeadOjbect есть около 30 свойств, которые могут содержать подчиненные свойства или свойство может быть списком и т. д. c .. Мне нужно заполнить ~ 30 объектов HeadObjects во время выполнения. Я уже пробовал это с различными библиотеками, такими как GenFu , nBuilder или Bogus .

Последние 2 имеют проблему с тем, что я должен заполнить свойства самостоятельно, только данные генерируются. Похоже, что GenFu может работать только с такими примитивными свойствами, как int, string, ... И если вы представляете HeadObject как root дерева, то будет

~ 300 узлов на дерево

Высота дерева: от 1 до 7 (!)

~ 30 Различных деревьев (HeadObjects)

, поэтому потребовались бы дни, чтобы записать все это самостоятельно, и обслуживание потребовало бы быть болью.

Я ценю любую идею.

ОБНОВЛЕНИЕ

Спасибо за ваши ответы! Как я могу инициализировать объекты? например, я получаю свойство Company моего головного объекта, а затем хочу инициализировать его, чтобы иметь возможность его заполнить. Мой метод (его рекурсивный) начинается так:

    private static T FillAllProperties<T>(T masterObject) where T : new()
    {
        try
        {

            Type masterType = masterObject.GetType();

            T headObject = new T();

            ......IF primitive Type fill it and return the value
            otherwise get Properties into firstProperties.......

       foreach (var propertyInfo in firstProperties)
       {
           var objectInstance = FillAllProperties(propertyInfo.PropertyType);

headObject.GetType().GetProperty($"{propertyInfo.Name}").SetValue(headObject, objectInstance, null);
           }

Теперь у меня есть 2 вопроса:

  1. Мой способ инициализации типа c generi правильный?
  2. при рекурсивном вызове я получаю следующую ошибку: "Тип 'System.Type' должен иметь конструктор publi c без параметров, чтобы использовать его в качестве параметра 'T' ....

Возможно, мне нужна еще одна "конструкция" для этого алгоритма, но как ..?

Ответы [ 2 ]

1 голос
/ 08 апреля 2020

Вы собираетесь go через глубокую боль ...

По сути, идея состоит в том, чтобы перебирать свойства объекта и случайным образом заполнять их.

Вы можете перебирать, используя YourObject.GetType (). GetProperties () , затем используя PropertyInfo.PropertyType , чтобы узнать тип.

Затем с каждым типом Proprety вы можете проверить, является ли он простым (т. Е. Int , double ...) структура или более сложный объект (используя Type.IsPrimitive , Type.IsClass или Type.IsValueType ).

  • Если это класс, вы рекурсивно вызываете тот же метод, потому что это означает, что у вас есть сложный тип.

  • Если это структура, то, возможно, вам следует перебирать поля вместо свойств?

  • Если это примитив, вы можете установите его значение с помощью PropertyInfo.SetValue () , но как вы собираетесь что-то рандомизировать? Вы должны выполнить переключение. Net базовых типов, а затем сгенерировать случайное значение для каждого типа.

Кстати, строка - это класс, а не примитив, поэтому вам нужно будет сделать специальный случай для этого.

Также, List<string> забавный, потому что это перечисляемый объект. Так что это еще один конкретный случай c.

И если вы хотите повеселиться, попробуйте Словарь, или, лучше, Tuple ...

В любом случае, не существует простого способа выполнить это. Ваш простой инструмент тестирования скоро станет кошмаром из-за всех случаев, которые вы даже не могли увидеть издалека ...

Возможно, есть лучший вариант для тестирования вашей программы, чем заполнение ее случайными значениями, которые не не имеет никакого реального значения?

1 голос
/ 08 апреля 2020

Если вы не знаете свойства во время выполнения, вам придется использовать Reflection. Но, начиная с 30 свойств, я бы, вероятно, использовал их независимо (или посмотрел, не допустил ли я ошибок в своем дизайне) Запись большого количества данных вручную слишком склонна к ошибкам.

Альтернативой может быть наличие интерфейса ISelfRandomizing с функцией SelfRandomize(), чтобы каждый тип ввода мог иметь свой собственный код рандомизации. И надеюсь, что люди действительно предоставят его.

Что-то, что может быть жизнеспособным для вашего случая: структуры по умолчанию используют отражение для сравнения. Что было бы эквивалентом базового класса для них, имеет основанный на отражении запасной код. Вам предлагается переопределить его, но если вы этого не сделаете, он просто «работает». Вы можете создать абстрактный базовый класс, который вы используете для всех этих классов. Таким образом, вам нужно всего лишь один раз написать код отражения.

Что касается фактической рандомизации: Random . Распространенной ошибкой является создание новых экземпляров Random в al oop. Не делай этого. Вы хотите сохранить один случайный экземпляр как можно дольше для оптимальной рандомизации. У меня нет разумного способа преобразовать возвращаемое целое число в строку, поэтому следующая лучшая неосмысленная вещь - создать большое случайное число и вызвать на нем ToString(). Это даст вам что-то , чтобы хотя бы поставить в эти места.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...