【问题标题】:How to fill a random object with random data at runtime如何在运行时用随机数据填充随机对象
【发布时间】:2020-04-09 19:12:59
【问题描述】:

我想为我的程序创建一个小测试工具,它填充随机对象的所有属性(编译时未知类型)。示例结构:

    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 个属性,这些属性可能包含子属性,或者一个属性可以是列表等。我需要在运行时填充大约 30 个 HeadObject。我已经尝试过使用不同的库,例如 GenFunBuilderBogus

最后2个问题是我必须自己填写属性才生成数据。 GenFu 看起来只能处理 int、string 等原始属性...如果您将 HeadObject 想象为树的根,那么就会有

~ 每棵树 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);
           }

现在我有两个问题:

  1. 我初始化泛型类型的方法正确吗?
  2. 在递归调用中,我收到以下错误:“类型 'System.Type' 必须具有公共无参数构造函数才能将其用作参数 'T'....

我可能需要对这个算法进行另一个“构造”,但是如何......?

【问题讨论】:

  • 那么到底是什么问题呢?如何使用反射来填充属性?如何为CompanyName 之类的东西生成随机字符串?除了查看一些不符合您要求的库之外,您还尝试过什么?
  • 您对生成的数据有要求吗?如果没有,您可以通过反射递归遍历所有属性,直到达到简单类型(intstring 等)。然后使用Random 填满它们。
  • “如何使用反射来填充属性”我不知道 C# 中的这种可能性。因此,我可以收集对象的所有属性并进行迭代,直到达到简单类型。那么 PropertyInfo.SetValue() 是正确的选择吗?感谢您的回复

标签: c# testing


【解决方案1】:

你将经历深深的痛苦......

基本上这个想法是遍历对象的属性并随机填充它们。

您可以使用YourObject.GetType().GetProperties() 进行迭代,然后使用PropertyInfo.PropertyType 来了解类型。

然后,对于每个 Proprety Type,您可以检查它是简单(即 int、double...)结构还是更复杂的对象(通过使用 Type.IsPrimitiveType.IsClassType.IsValueType)。

  • 如果它是一个类,你递归调用相同的方法,因为这意味着你有一个复杂的类型。

  • 如果它是一个结构,那么也许您应该遍历字段而不是属性?

  • 如果它是一个原语,你可以使用PropertyInfo.SetValue() 设置它的值,但是你要如何随机化任何东西呢?您需要对 .Net 基本类型进行切换,然后为每种类型随机生成一个值。

顺便说一句,字符串是一个类,而不是原始类型,所以你需要为它做一个特例。

另外,List&lt;string&gt; 是一个有趣的对象,因为它是一个 Enumerable 对象。所以这是另一个具体案例。

如果你想玩得开心,试试字典,或者更好的元组......

无论如何,没有简单的方法来执行此操作。您的简单测试工具很快就会成为一场噩梦,因为您甚至无法从远处看到所有案例......

也许有更好的选择来测试你的程序,而不是用没有任何实际意义的随机值填充它?

【讨论】:

  • 谢谢!我目前正在努力初始化我的泛型类型。因为我需要初始化任何属性才能正确分配它?但是如何?我已将我当前的状态发布为上面的更新
【解决方案2】:

如果您不知道运行时的属性,则必须使用反射。但是从 30 个属性开始,我可能无论如何都会使用它(或者看看我是否在设计中犯了任何错误)。手动写这么多太容易出错了。

另一种选择可能是使用带有SelfRandomize() 函数的ISelfRandomizing 接口,因此每个类型输入都可以携带它自己的随机化代码。并希望人们真正提供它。

对您的情况可能可行的事情:结构默认使用反射进行比较。对他们来说,相当于基类的东西有基于反射的后备代码。邀请您覆盖它,但如果您不这样做,它只会“起作用”。您可以创建一个用于所有这些类的抽象基类。这样你只需要编写一次反射代码。

至于实际随机化:Random。一个常见的错误是在循环中创建 Random 的新实例。不要那样做。您希望尽可能长时间地保留单个 Random 实例,以实现最佳随机化。我没有明智的方法将 Integer 返回转换为字符串,因此下一个最好的不明智的事情是创建一个大随机数并在其上调用 ToString()。这会给你一些东西至少放在那些地方。

【讨论】:

    猜你喜欢
    • 2013-12-29
    • 2018-12-08
    • 1970-01-01
    • 1970-01-01
    • 2011-03-23
    • 2016-07-22
    • 2017-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多