在Visual Studio 2015中从代码覆盖中排除自动属性

本文关键字:排除 属性 覆盖 Visual Studio 2015 代码 | 更新日期: 2023-09-27 18:10:50

我刚把一堆项目升级到VS2015/c# 6。

现在MSTest的代码覆盖率分析报告了一些自动属性没有被单元测试覆盖。在Visual Studio 2013中,情况并非如此,我怀疑这可能与c# 6中新的自动属性特性有关。

处理由此产生的所有误报反而违背了代码覆盖工具的目的,因为它实际上使识别缺乏测试覆盖的实际代码变得不可能。我们不想为所有的dto编写单元测试,而且我真的不想在整个项目中用ExcludeFromCodeCoverage注释每一个自动属性。

我已经创建了一个工作的MCVE在https://github.com/iaingalloway/VisualStudioCodeCoverageIssue


    在Visual Studio 2013 Premium或Ultimate中打开VisualStudio2013.sln
  • 单击测试->分析代码覆盖率->所有测试。
  • 观察"代码覆盖结果"窗口报告0块"未覆盖"。

    Open VisualStudio2015.sln in Visual Studio 2015 Enterprise
  • 单击测试->分析代码覆盖率->所有测试。
  • 观察"Code Coverage Results"窗口报告1个Block "Not Covered" (ExampleDto.Value的getter)

是否可以在Visual Studio 2015中配置内置的代码覆盖工具以忽略像Visual Studio 2013那样的自动属性?

在Visual Studio 2015中从代码覆盖中排除自动属性

作为一种解决方法,您可以在.runsettings文件中添加以下内容:-

<RunSettings>
  <DataCollectionRunSettings>
    <DataCollector ...>
      <Configuration>
        <CodeCoverage>
          <Functions>
            <Exclude>
              <Function>.*get_.*</Function>
              <Function>.*set_.*</Function>
            </Exclude>
          ...

这不是一个很好的解决方案,但只要你不使用任何函数的名称中有"get_"或"set_",它应该得到你需要的行为

我不喜欢过滤所有get/set方法,特别是因为我有时编写需要测试的get和set逻辑。对我来说,对于相对简单的模型的基本覆盖,以下两个xUnit测试工作得很好:

    public class ModelsGetSetTest
    {
        [ClassData(typeof(ModelTestDataGenerator))]
        [Theory]
        public void GettersGetWithoutError<T>(T model)
        {
            var properties =
                typeof(T).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            for (var i = 0; i < properties.Length; i++)
            {
                var prop = properties[i];
                if (prop.GetGetMethod(true) != null)
                    prop.GetValue(model);
            }
        }
        [ClassData(typeof(ModelTestDataGenerator))]
        [Theory]
        public void SettersSetWithoutError<T>(T model)
        {
            var properties =
                typeof(T).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            for (var i = 0; i < properties.Length; i++)
            {
                var prop = properties[i];
                if (prop.GetSetMethod(true) != null)
                    prop.SetValue(model, null);
            }
        }
        public class ModelTestDataGenerator : IEnumerable<object[]>
        {
            private readonly List<object[]> _data = new List<object[]>();
            public ModelTestDataGenerator()
            {
                var assembly = typeof(Program).Assembly;
                var nsprefix = $"{typeof(Program).Namespace}.{nameof(Models)}";
                var modelTypes = assembly.GetTypes()
                    .Where(t => t.IsClass && !t.IsGenericType) // can instantiate without much hubbub
                    .Where(t => t.Namespace.StartsWith(nsprefix)) // is a model
                    .Where(t => t.GetConstructor(Type.EmptyTypes) != null) // has parameterless constructor
                    .ToList();
                foreach (var modelType in modelTypes) _data.Add(new[] {Activator.CreateInstance(modelType)});
            }
            public IEnumerator<object[]> GetEnumerator()
            {
                return _data.GetEnumerator();
            }
            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
        }
    }

更新于2020-03-18:此版本使用反射来查找特定命名空间下的模型。

我认为[ExcludeFromCodeCoverage]是你唯一的选择。这只是你必须做的一次性的事情。就我个人而言,我确实会在属性getter/setter上编写单元测试,特别是在WPF中,我想确保属性更改通知发生。