Прежде всего: для не рекомендуется создавать тестовые объекты со случайными значениями.
Цель вашего модульного теста - найти ошибки в классе, который вы тестируете. Ошибки в текущей версии и в будущих версиях. Класс вашего устройства не создан для поиска ошибок, возникающих при использовании обычного ввода.Эти ошибки уже обнаружены при первом запуске программы после изменения кода. Основная цель - найти ошибки, которые вы не найдете при нормальной работе программы.
Ваш юнит-тест будет только доверять вашему коду, если он обнаружит ошибки в редких случаях.
Обычно они называются краевых условия: самое низкое значение, максимальное значение, пустое значение, максимальное количество значений, отрицательных значений, нулевых значений и т.д.
Создание класса заполнен случайные значения прикладывают много усилий для создания кода, который создает тестовый объект, который, вероятно, найдет те же ошибки, что и любой объект, не относящийся к краю, который вы можете придумать в течение минуты. Вам нужно будет запустить свой тест миллион раз, прежде чем вы проверите свой код с пустым массивом или с отрицательным числом элементов или даже с первичным номером и т. Д.
Поэтому не прилагайте никаких усилий при создании единичный тест со случайным значением.
Только несколько случаев с нормальным входом и попробуйте найти множество тестов с краевыми условиями.
Однако создание фабрики, которая создаст любой класс любого типа, заполненный случайными значениями, может быть интересным упражнением.
Прежде всего, вы должны только инициализировать свойства, доступные для записи, поэтому вы должны их проверить. Используйте 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;
}
Придумайте что-нибудь подобное для создания структуры или массива.
Посмотрите на [AutoFixture] (https://github.com/AutoFixture/AutoFixture). Он может предоставлять данные случайных испытаний и многое другое. (Не мой нисходящий, на самом деле это правильный вопрос) –
@SriramSakthivel - AutoFixture отлично, используйте его довольно часто. – Ric
спасибо. Я буду использовать его. Только ради этого, что было бы хорошим решением для вышеупомянутой проблемы? –