2015-08-04 2 views
4

Я использую отражение, чтобы заполнить данную C# класс с тестовыми даннымиЗаполните класс с тестовыми данными

public object CreateObj(Type type) 
{ 
    var obj = Activator.CreateInstance(type); 
    var fields = type.GetFields(); 
    foreach (var field in fields) 
    { 
     field.SetValue(obj, GetRnd(field.FieldType)); 
    } 

    return obj; 
} 

GetRnd() Функция установите значение в соответствии с типом поля:

private object GetRnd(Type type) 
{ 
    if (type == typeof(int)) 
    { 
     return 4; 
    } 
    else if (type == typeof(string)) 
    { 
     return "text"; 
    } 
    else 
    { 
     throw new Exception(); 
    } 

} 

Это работает до тех пор, пока я перехожу на CreateObj() в подходящий класс. Я бы хотел, чтобы он работал даже с базовыми типами (string, int и т. Д.). К настоящему времени я получаю «SetType(): Не могу установить исключение константного поля при передаче простого« int ».

+1

Посмотрите на [AutoFixture] (https://github.com/AutoFixture/AutoFixture). Он может предоставлять данные случайных испытаний и многое другое. (Не мой нисходящий, на самом деле это правильный вопрос) –

+2

@SriramSakthivel - AutoFixture отлично, используйте его довольно часто. – Ric

+0

спасибо. Я буду использовать его. Только ради этого, что было бы хорошим решением для вышеупомянутой проблемы? –

ответ

1

Проверьте тип, если это значение «Тип.IsValue», что означает, что параметр pass pass type является скалярным.

-1

Вы не задать вопрос, но вот что я думаю вы хотите знать:

Как я могу изменить этот код, чтобы установить постоянный или только для чтения полей?

Вы не можете. Это только для чтения.

Как я могу получить эту работу с int и другими типами

Ну, Вы можете предотвратить ошибки путем проверки только для чтения или постоянных полей:

foreach (var field in fields) 
{ 
    if (!(field.IsInitOnly || field.IsLiteral)) 
     field.SetValue(obj, GetRnd(field.FieldType)); 
} 

Могу ли я использовать этот класс для генерации случайного целого числа или строки?

Не изменяя свои поля. Примитивные типы, такие как int и string, неизменяемы. Единственный способ изменить значение переменной - это перезаписать ее новым значением. Таким образом, вы должны будете обрабатывать случаи для неизменных типов:

static Random rand = new Random(); 

public object CreateObj(Type type) 
{ 

    if(type == typeof(int)) return GetRnd(type); 
    if(type == typeof(string)) return GetRnd(type); 

    var obj = Activator.CreateInstance(type); 
    var fields = type.GetFields(); 
    foreach (var field in fields) 
    { 
     field.SetValue(obj, GetRnd(field.FieldType)); 
    } 

    return obj; 
} 

Как еще можно было бы улучшить?

  • Это только устанавливает поля, не свойства. Если у вас есть класс со свойствами, завернуть приватные поля, то они не будут установлены
  • Он не будет работать для типов, которые не имеют общественный конструктор без параметров
2

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

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

Ваш юнит-тест будет только доверять вашему коду, если он обнаружит ошибки в редких случаях.

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

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

Поэтому не прилагайте никаких усилий при создании единичный тест со случайным значением.

Только несколько случаев с нормальным входом и попробуйте найти множество тестов с краевыми условиями.

Однако создание фабрики, которая создаст любой класс любого типа, заполненный случайными значениями, может быть интересным упражнением.

Прежде всего, вы должны только инициализировать свойства, доступные для записи, поэтому вы должны их проверить. Используйте System.PropertyInfo.IsWritable.

Кроме того, расширить функции GetRnd таким образом, что он будет инициализировать любые примитивные типы использования System.Type.IsPrimitive и System.Type.GetTypeCode()

Ваш класс потерпит неудачу, если один из ваших свойств перезаписываемых класс. В этом случае вы можете рекурсивно инициализировать этот класс. Использовать System.Type.IsClass

Вы также хотите инициализировать классы с помощью нестандартных конструкторов? Используйте System.Type.GetConstructors, чтобы узнать, есть ли у него и проверить, какие другие конструкторы доступны.

Как насчет массива?

Дополнительная сложность: если ваш класс имеет свойство только для чтения, в котором вы можете изменить возвращаемые значения.

class RandomObjectFactory 
{ 
    // creates an object of type T that has a default constructor 
    public T CreateObject<T>() where T: class, new() 
    { 
     ... 

Этот метод предпочтителен выше метод с параметром типа, потому что с помощью этого метода компилятор жалуется, если вы пытаетесь написать:

MyClass m = CreateObject<YourClass>(); 

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

Точно так же имеет смысл создать метод для примитивных типов:

public T CreatePrimitive<T> where T: struct, IConvertible 
{ 
    ... 

Это предотвратит ошибки, такие как:

int i = Create(typeof(Form)); 

код для создания объекта:

public T CreateObject<T>() where T: class, new() 
{ 
    var obj = Activator.CreateInstance<T>(); 
    foreach (var property in typeof(T).GetProperties() 
     .Where(property => property.CanWrite)) 
    { 
     if (property.PropertyType.IsPrimitive) 
     { 
      property.SetValue(obj, this.CreatePrimitive 
       (Type.GetTypeCode(property.PropertyType))); 
     } 
     else if (property.PropertyType.IsClass) 
     { 
      property.SetValue(obj, this.CreatObject... 

Здесь у нас есть проблемы: мы не можем передать свойство .PropertyType.

Чтобы решить эту проблему: создайте закрытую функцию CreateObject, которая принимает system.Type и возвращает объект. Поскольку это личное, никто не может ошибочно использовать его.

private object CreateObject(Type type) 
{ 
    var obj = Activator.CreateInstance(type); 
    foreach (var property in typeof(T).GetProperties() 
     .Where(property => property.CanWrite)) 
    { 
     if (property.PropertyType.IsPrimitive) 
     { 
      property.SetValue(obj, this.CreatePrimitive 
       (Type.GetTypeCode(property.PropertyType))); 
     } 
     else if (property.PropertyType.IsClass) 
     { 
      property.SetValue(obj, this.CreateObject (property.PropertyType); 
     } 
    } 
    return obj; 
} 

private object CreatePrimitive(TypeCode typeCode) 
{ 
    switch (typeCode) 
    { 
     case TypeCode:Boolean: 
      return this.rnd.Next(2) == 0; 
     case TypeCode.Byte: 
      return (Byte)this.rnd.Next(Byte.MinValue, Byte.MaxValue); 
     case TypeCode.DateTime: 
      long ticks = (long)((DateTime.MaxValue.Ticks - DateTime.MinValue.Ticks) * rnd.NextDouble() + DateTime.MinValue.Ticks); 
      return new DateTime(ticks); 
     // etc. 
    } 
    return obj; 
} 

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

+0

если я спрошу «как сделать» что-то, пожалуйста, не отвечайте «вы должны сделать это вместо этого». Я не прошу лучшего решения (которое ВСЕГДА существует), просто как решить непосредственную проблему в заданной среде на данном дерьмо. Отмечено как inapproriate –

+0

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