如何将这个foreach重写为上一个Linq表达式的一部分

本文关键字:Linq 上一个 表达式 一部分 重写 foreach | 更新日期: 2024-05-04 15:30:14

我正在用自定义属性SpecificationAttributeVerificationAttribute装饰我的MSTest测试,稍后我将使用它们来生成html测试规范报告。

属性如下:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class SpecificationAttribute : Attribute
{
    public SpecificationAttribute(int step, string text)
    {
        Step = step;
        Text = text;
    }
    public int Step { get; set; }
    public string Text { get; set; }
}

我写了一个测试,它断言一个测试方法在使用属性时必须有唯一的步骤。例如,以下用法不能通过我的测试,因为它应该是:

[Specification(1, "Click Button)]
[Verification(1, "Verify popup")]
[Specification(1, "Click close")]
[Verification(2, "Verify popup disappears")]

我的测试是这样的:

[TestMethod]
public void TestForNoDuplicateStepsOnMethod()
{
    var specificationMethods = Assembly.GetExecutingAssembly().GetTypes()
        .Where(type =>
            type.GetCustomAttribute<CompilerGeneratedAttribute>() == null &&
                type.GetCustomAttribute<TestClassAttribute>() != null)
        .SelectMany(type => type.GetMethods())
        .Where(methodInfo =>
            methodInfo.GetCustomAttribute<TestMethodAttribute>() != null &&
            methodInfo.GetCustomAttributes<SpecificationAttribute>().Any())
        .ToArray();
    foreach (var method in specificationMethods)
    {
        var specificationAttributes = method.GetCustomAttributes<SpecificationAttribute>();
        var duplicates = specificationAttributes.GroupBy(s => s.Step).Where(grp => grp.Count() > 1).SelectMany(x => x).ToList();
        if (duplicates.Any())
        {
            var initialMessage = $@"{Environment.NewLine}{method.DeclaringType}.{method.Name} contains several SpecificationAttribute with the same step number." + Environment.NewLine + Environment.NewLine;
            var message = duplicates.Aggregate(initialMessage, (s, attribute) => s + attribute.Step + " " + attribute.Text + Environment.NewLine);
            Assert.Fail(message);
        }
    }
}

我想重写最后一部分,使其成为Linq查询的一部分。这可能吗?此外,我当前的测试只输出一个失败的方法。如果Linq查询可以包括在唯一步骤号上具有失败条件的所有方法,那将是可取的。

如何将这个foreach重写为上一个Linq表达式的一部分

(经过编辑以解决阳性检测的问题)试试这个,但IMHO,它更难阅读。

[TestMethod]
public void TestForNoDuplicateStepsOnMethod()
{
    var errors = Assembly.GetExecutingAssembly().GetTypes()
        .Where(type =>
            type.GetCustomAttribute<CompilerGeneratedAttribute>() == null &&
                type.GetCustomAttribute<TestClassAttribute>() != null)
        .SelectMany(type => type.GetMethods())
        .Where(methodInfo =>
            methodInfo.GetCustomAttribute<TestMethodAttribute>() != null &&
            methodInfo.GetCustomAttributes<SpecificationAttribute>().Any())
        .Select(method =>
            method.GetCustomAttributes<SpecificationAttribute>()
        .GroupBy(s => s.Step)
            .Where(grp => grp.Count() > 1)
            .Select(x => x.Aggregate(
                $@"{Environment.NewLine}{method.DeclaringType}.{method.Name} contains several SpecificationAttribute with the same step number." 
                + Environment.NewLine,
                (s, attribute) => s + attribute.Step + " " + attribute.Text + Environment.NewLine))
                .Aggregate("", (s, message) => s + message))
            .Aggregate("", (s, message) => s + message);
        Assert.AreEqual("", errors);
}

如果您不需要对var规范进行更多操作,您可以尝试以下方法:

 [TestMethod]
    public void TestForNoDuplicateStepsOnMethod()
    {
        Assembly.GetExecutingAssembly().GetTypes()
            .Where(type =>
                type.GetCustomAttribute<CompilerGeneratedAttribute>() == null &&
                    type.GetCustomAttribute<TestClassAttribute>() != null)
            .SelectMany(type => type.GetMethods())
            .Where(methodInfo =>
                methodInfo.GetCustomAttribute<TestMethodAttribute>() != null &&
                methodInfo.GetCustomAttributes<SpecificationAttribute>().Any())
            .ToList().ForEach (method=> 
        {
            var specificationAttributes = method.GetCustomAttributes<SpecificationAttribute>();
            var duplicates = specificationAttributes.GroupBy(s => s.Step).Where(grp => grp.Count() > 1).SelectMany(x => x).ToList();
            if (duplicates.Any())
            {
                var initialMessage = $@"{Environment.NewLine}{method.DeclaringType}.{method.Name} contains several SpecificationAttribute with the same step number." + Environment.NewLine + Environment.NewLine;
                var message = duplicates.Aggregate(initialMessage, (s, attribute) => s + attribute.Step + " " + attribute.Text + Environment.NewLine);
                Assert.Fail(message);
            }
    }
  }
}