【问题标题】:Using reflection to test that all collection properties of classes will be instantiated使用反射测试类的所有集合属性都会被实例化
【发布时间】:2016-03-20 13:11:50
【问题描述】:

我正在尝试制作一个单元测试,它将检查给定程序集,所有具有空构造函数的非抽象类在实例化时都会实例化它们的集合属性。这是正在测试的系统:

namespace MyProject.Dto.Things
{
    public class Item
    {
        public Item()
        {
            // Second batch of props should be instantiated here...
        }

        // Properties that my test doesn't/shouldn't care about:
        public int IntProp { get; set; }
        public string StringProp { get; set; }

        // Properties my test should account for:
        public List<string> ListProp { get; set; }
        public IList<string> IListProp { get; set; }
        public ISet<string> ISetProp { get; set; }
        public ICollection<string> ICollectionProp { get; set; }
        public IDictionary<string, string> IDictionaryProp { get; set; }
        public Stack<string> StackProp { get; set; }
        public string[] ArrayProp { get; set; }
    }
}

我的第一次尝试是这样的:

[TestFixture]
public class DtoTests
{
    [Test]
    public void NamespaceDtos_WhenDefaultConstructorIsCalled_InstantiatesCollectionProperties()
    {
        bool testWasMeaningful = false;

        foreach (var type in GetEntityTypesWithDefaultConstructor())
        {
            var instance = Activator.CreateInstance(type);
            var collectionProps = type
                .GetProperties()
                .Where(p => typeof(ICollection<>).IsAssignableFrom(p.PropertyType));

            foreach (var prop in collectionProps)
            {
                var val = prop.GetValue(instance);
                Assert.That(val, Is.Not.Null.And.Empty, string.Format("[{0}.{1}]", type.Name, prop.Name));
                testWasMeaningful = true;
            }
        }

        Assert.That(testWasMeaningful, "Expected at least one assertion.");
    }

    private IEnumerable<Type> GetEntityTypesWithDefaultConstructor()
    {
        return Assembly
            .GetAssembly(typeof(MyProject.Dto.Things.Item))
            .GetTypes()
            .Where(t => !t.IsAbstract)
            .Where(t => t.GetConstructor(Type.EmptyTypes) != null);
    }
}

但是,这不起作用,因为Where 子句没有从我的其他程序集中获取正确的属性。我的测试失败了,因为它没有测试单个属性。


尝试修复 1 号

我试过这样this answer

var collectionProps = type
    .GetProperties()
    .Where(m => m.PropertyType.IsGenericType && m.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>));

但这只会捕获Item.ICollectionProp,而无法测试所有其他人。


尝试修复 2 号

其次,我尝试过this answer to another question(逐字使用GetICollectionOrICollectionOfTProperties 方法),如下所示:

var collectionProps = type
    .GetICollectionOrICollectionOfTProperties();

但具有讽刺意味的是,即使 Item.ICollectionProp 没有被实例化,它也会错误地通过测试。


尝试修复 3 号

我也尝试过测试所有 IEnumerable 属性,如下所示:

var collectionProps = type
    .GetProperties()
    .Where(p => typeof(IEnumerable).IsAssignableFrom(p.PropertyType));

但这在Item.StringProp 上会失败,因为stringIEnumerable,我不想在这里测试。


我不确定我哪里出错了,尤其是 nr 2。我什至认为我的问题与那个问题是重复的,如果我只是让解决方案起作用的话。

底线:(X)我如何测试具有空构造函数的类的所有集合属性在类被实例化时被实例化,和/或(Y)我如何使用反射找到一个类型的所有集合属性?

【问题讨论】:

    标签: c# unit-testing generics reflection


    【解决方案1】:

    我建议使用这个辅助函数来查找所有基于ICollectionICollection&lt;&gt; 的类型:

    private static bool IsOrImplementsICollection(Type t)
    {
        if (t == typeof (ICollection) || (t.IsGenericType && t.GetGenericTypeDefinition() == typeof (ICollection<>)))
            return true;
        return t.GetInterfaces().Any(IsOrImplementsICollection);
    }
    

    在您的测试中,您可以将 where 子句更改为:

    var collectionProps = type
        .GetProperties()
        .Where(x => IsOrImplementsICollection(x.PropertyType));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 2011-03-05
      • 1970-01-01
      • 2020-06-20
      • 1970-01-01
      • 2012-06-22
      • 1970-01-01
      相关资源
      最近更新 更多