Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用测试数据填充一个类_C#_Unit Testing_Reflection - Fatal编程技术网

C# 用测试数据填充一个类

C# 用测试数据填充一个类,c#,unit-testing,reflection,C#,Unit Testing,Reflection,我使用反射用测试数据填充给定的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 o

我使用反射用测试数据填充给定的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()
一个合适的类,这就可以工作。我想让它甚至可以与基本类型(字符串、int等)一起工作
现在,当我传递一个简单的“int”时,我得到了一个“SetType():无法设置常量字段”异常。检查该类型是否为值“type.IsValue”,这意味着类型传入参数是标量类型。

您没有问问题,但我想您想知道:

如何将此代码更改为设置常量或只读字段

你不能。它们是只读的

我怎样才能让它与
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;
}
还有什么可以改进的

  • 它只设置字段,不设置属性。如果您有一个具有包装私有字段的属性的类,则不会设置它们
  • 它不适用于没有公共无参数构造函数的类型
首先:对于单元测试,不建议使用随机值创建测试对象

单元测试的目的是在正在测试的类中查找错误。当前版本和未来版本中的错误。创建unit类不是为了查找使用普通输入时发生的错误。这些错误在代码更改后第一次运行程序时已被发现。主要目的是查找正常运行程序时无法找到的错误

只有在极少数情况下发现错误时,单元测试才会给代码带来信心

通常称为边缘条件:最低值、最高值、空值、最大值数、负值、空值等

创建一个充满随机值的类需要花费大量精力来创建代码,以创建一个测试对象,该测试对象可能会在一分钟内发现与您可以发明的任何非边缘测试对象相同的错误。在使用空数组、负数元素或偶数主数等测试代码之前,您必须运行一百万次测试

因此,不要在创建带有随机值输入的单元测试时投入任何精力

只有少数具有正常输入的情况,并尝试找到大量具有边缘条件的测试

然而,创建一个工厂来创建任何类型的、填充了随机值的类可能是一个有趣的练习

首先,您应该只初始化可写的属性,因此您应该检查它们是否可写。使用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()
    {
        ...
创建对象的代码如下:

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...

发明类似的东西来创建结构或数组。

看一看。它可以提供随机测试数据和更多。(不是我的反对票,事实上这是一个有效的问题)@SriramSakthivel-AutoFixture很棒,经常使用它。谢谢。我会用的。就为了它,对于上述问题,什么样的解决方案才是好的呢?我想说的是AutoFac。它是专门为解决这个问题而设计的。它是开源的,你也可以从nuget下载。如果您想自己解决这个问题,那么您将编写大量的代码,但没有回报;)基本上AutoFixture是做什么的。如果我问“如何做”某件事,请不要回答“你应该做这个而不是那个”。我不是在要求一个更好的解决方案(它总是存在的),而是如何在给定的环境和给定的垃圾上解决眼前的问题。标记为Stackoverglow帮助中心的不当摘录-我们的模型:粗鲁和轻视语言是不好的。你的语气应该与你与你尊敬的人以及你想尊敬的人交谈的方式相匹配。如果你没有时间礼貌地说些什么,就留给有礼貌的人吧;
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...
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;
}