用测试数据填充 class
Fill a class with test data
我正在使用反射填充给定的 C# class 测试数据
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();
}
}
只要我将适当的 class 传递给 CreateObj()
,它就可以工作。我想让它与基本类型(字符串、整数等)一起工作。
到目前为止,当我传递一个简单的 "int".
时,我得到一个 "SetType(): Cannot set a constant field" 异常
检查类型是否为值'Type.IsValue',这意味着传入参数的类型是标量类型。
你没有提出问题,但这是我认为你想知道的:
How can I change this code to set constant or read-only fields?
你不能。它们是 只读的。
How can I get this to work with int
and other types
好吧,您可以通过检查只读或常量字段来防止错误:
foreach (var field in fields)
{
if (!(field.IsInitOnly || field.IsLiteral))
field.SetValue(obj, GetRnd(field.FieldType));
}
Can I use this class to generate a random integer or string?
不是通过更改它的字段。 int
和 string
等基本类型是不可变的。 "change" 变量值的唯一方法是用新值覆盖它。所以你需要处理不可变类型的情况:
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;
}
How else can this be improved?
- 它只设置字段,不设置属性。如果您的 class 具有包装私有字段的属性,那么它们将不会被设置
- 它不适用于没有 public 无参数构造函数的类型
First of all: for a unit test it is not advised to create test objects with random values.
单元测试的目的是找出正在测试的 class 中的错误。当前版本和未来版本中的错误。您的单元class 不是为了查找使用正常输入时出现的错误而创建的。代码更改后,您第一次 运行 程序时已经发现了这些错误。主要目的是找出在 运行 正常运行程序时不会发现的错误。
Your unit test would only give confidence in your code if it will find errors in rare cases.
通常称为边缘条件:最低值、最高值、空值、最大值数、负值、空值等
创建一个充满随机值的 class 需要花费大量精力来创建创建测试对象的代码,该测试对象可能会发现与您可以在分钟。在使用空数组、负数元素或偶数主数等测试代码之前,您必须 运行 测试一百万次
Therefore don't put any effort in creating a unit test with random value input.
只有少数输入正常的情况,尽量多找边缘条件的测试。
但是,创建一个工厂来创建任何 class 填充随机值的任何类型可能是一个有趣的练习。
首先你应该只初始化可写的属性,因此你应该检查它们是否是。使用 System.PropertyInfo.IsWritable.
此外,扩展您的 GetRnd 函数,使其初始化任何基本类型 使用 System.Type.IsPrimitive 和 System.Type.GetTypeCode()
如果您的可写属性之一是 class,您的 class 将失败。在这种情况下,您可以递归地初始化 class。使用 System.Type.IsClass
您还想用非默认构造函数初始化 classes 吗?使用 System.Type.GetConstructors 查看它是否有并检查其他可用的构造函数。
数组怎么样?
额外的难度:如果您的 class 有一个只读的 属性,您可以在其中更改返回值。
class RandomObjectFactory
{
// creates an object of type T that has a default constructor
public T CreateObject<T>() where T: class, new()
{
...
此方法优于带有 Type 参数的方法,因为如果您尝试编写此方法,编译器会报错:
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...
这里我们遇到了问题:我们无法通过 property.PropertyType。
要解决这个问题:创建一个私有函数 CreateObject,它接受一个 system.Type 和 returns 一个对象。因为这个是私有的,任何人都不能误用它。
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;
}
发明类似于创建结构或数组的东西。
我正在使用反射填充给定的 C# class 测试数据
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();
}
}
只要我将适当的 class 传递给 CreateObj()
,它就可以工作。我想让它与基本类型(字符串、整数等)一起工作。
到目前为止,当我传递一个简单的 "int".
检查类型是否为值'Type.IsValue',这意味着传入参数的类型是标量类型。
你没有提出问题,但这是我认为你想知道的:
How can I change this code to set constant or read-only fields?
你不能。它们是 只读的。
How can I get this to work with
int
and other types
好吧,您可以通过检查只读或常量字段来防止错误:
foreach (var field in fields)
{
if (!(field.IsInitOnly || field.IsLiteral))
field.SetValue(obj, GetRnd(field.FieldType));
}
Can I use this class to generate a random integer or string?
不是通过更改它的字段。 int
和 string
等基本类型是不可变的。 "change" 变量值的唯一方法是用新值覆盖它。所以你需要处理不可变类型的情况:
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;
}
How else can this be improved?
- 它只设置字段,不设置属性。如果您的 class 具有包装私有字段的属性,那么它们将不会被设置
- 它不适用于没有 public 无参数构造函数的类型
First of all: for a unit test it is not advised to create test objects with random values.
单元测试的目的是找出正在测试的 class 中的错误。当前版本和未来版本中的错误。您的单元class 不是为了查找使用正常输入时出现的错误而创建的。代码更改后,您第一次 运行 程序时已经发现了这些错误。主要目的是找出在 运行 正常运行程序时不会发现的错误。
Your unit test would only give confidence in your code if it will find errors in rare cases.
通常称为边缘条件:最低值、最高值、空值、最大值数、负值、空值等
创建一个充满随机值的 class 需要花费大量精力来创建创建测试对象的代码,该测试对象可能会发现与您可以在分钟。在使用空数组、负数元素或偶数主数等测试代码之前,您必须 运行 测试一百万次
Therefore don't put any effort in creating a unit test with random value input.
只有少数输入正常的情况,尽量多找边缘条件的测试。
但是,创建一个工厂来创建任何 class 填充随机值的任何类型可能是一个有趣的练习。
首先你应该只初始化可写的属性,因此你应该检查它们是否是。使用 System.PropertyInfo.IsWritable.
此外,扩展您的 GetRnd 函数,使其初始化任何基本类型 使用 System.Type.IsPrimitive 和 System.Type.GetTypeCode()
如果您的可写属性之一是 class,您的 class 将失败。在这种情况下,您可以递归地初始化 class。使用 System.Type.IsClass
您还想用非默认构造函数初始化 classes 吗?使用 System.Type.GetConstructors 查看它是否有并检查其他可用的构造函数。
数组怎么样?
额外的难度:如果您的 class 有一个只读的 属性,您可以在其中更改返回值。
class RandomObjectFactory
{
// creates an object of type T that has a default constructor
public T CreateObject<T>() where T: class, new()
{
...
此方法优于带有 Type 参数的方法,因为如果您尝试编写此方法,编译器会报错:
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...
这里我们遇到了问题:我们无法通过 property.PropertyType。
要解决这个问题:创建一个私有函数 CreateObject,它接受一个 system.Type 和 returns 一个对象。因为这个是私有的,任何人都不能误用它。
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;
}
发明类似于创建结构或数组的东西。