15

我正在做一个大型项目,即使有 1000 个自动化测试和 100% 的代码覆盖率中的 10 个,我们也会收到大量错误。我们得到的错误中大约 95% 是 NullReferenceExceptions。

有没有办法在编译时强制执行空值检查?

除此之外,有没有办法在单元测试中自动执行空检查,而不必自己为空案例编写测试?

4

13 回答 13

18

您应该查看Code Contracts。静态检查器仅适用于高端 VS 版本,但这基本上就是您所追求的。

网上有很多资源,<plug>你也可以阅读 C# 深度第 2 版中关于代码契约章节的预发布版本 -免费下载第 15 章</plug>(关于最新最好的代码合同版本,这一章有点过时了,但没什么大不了的。)

于 2010-02-25T21:22:43.273 回答
4

100% 的代码覆盖率没有任何意义。

这是一种虚假的安全感。

您唯一要衡量的是您正在执行所有代码行。

不是:

  • 这些代码行是所有应该存在的代码行
  • 这些代码行是否正确运行(您是否在测试所有边缘情况?)

例如,如果您处理火灾的程序包含 1 个步骤“跑出建筑物”,那么即使这种情况发生在 100% 的情况下,也许更好的程序是“警告消防部门,尝试停止火,然后如果一切都失败了,就会熄灭”。

如果您没有专门进入并添加代码,无论是代码协定 (.NET 4.0) 还是特定的 IF 语句 (<4.0),C# 中都没有任何内置功能可以帮助您解决此问题。

于 2010-02-25T21:21:47.910 回答
3

C# 8 引入了不可为空的引用类型

可以修改 .Net 项目以启用Nullable选项:

<LangVersion>8.0</LangVersion>
<Nullable>enable</Nullable>

编译器将能够区分

  • stringstring?

  • NonNullableClassNullableClass?

于 2019-05-02T19:44:06.930 回答
1

这不是技术解决方案,而是社会解决方案。当引用类型被外部代码以任何方式修改(另一个方法调用等)时,只需在您的环境中使访问引用类型而不检查 null 成为不可接受的。单元测试并不能取代良好的老式代码审查。

于 2010-02-25T21:23:30.097 回答
1

有没有办法在编译时强制执行空值检查?

没有。编译器无法确定运行时引用变量是否指向 null。

并且排除产生空值的语句(集合和返回)也是不够的。考虑:

public class Customer
{
  public List<Order> Orders {get;set;}
}
  //now to use it
Customer c = new Customer;
Order o = c.Orders.First(); //oops, null ref exception;
于 2010-02-25T21:25:41.080 回答
1

1)我认为,Resharper可以建议您检查代码中的一些关键位置。例如,它建议添加 [null reference check code],如果您允许,则添加它。

试试看。当然,如果您需要,它将增加您的经验。

2)在开发应用程序的早期阶段在您的代码中使用“快速失败”模式(或断言、断言)

于 2010-02-25T23:01:52.700 回答
1

防御性编程只能让你走这么远......也许更好地捕捉异常并像其他任何事情一样处理它。

于 2010-02-25T23:25:13.710 回答
0

我可能错了,但我认为 FxCop 有一条规则建议您在代码中添加空引用检查。您可以尝试通过该工具运行您的程序集,看看它要说什么。

于 2010-02-25T22:22:12.150 回答
0

查看Gendarme,它可以在构建后与您的测试一起运行(如果您愿意,可以在它们之前运行)并且有一些与null检查相关的规则。您也可以相当简单地编写自己的。

于 2010-02-25T22:29:51.500 回答
0

C# 3 不可能实现这些。你必须使用像 Spec# 这样的东西……我认为 C#4 可能内置了一些内容,但我不确定。

规格#:http ://research.microsoft.com/en-us/projects/specsharp

于 2010-02-25T21:20:17.197 回答
0

您不能在编译时进行空值检查,因为在编译时对象只是类型,并且只有在运行时类型才会转换为具有具体值的实例......这里为空。

于 2010-02-25T21:22:48.843 回答
0

也许您应该看一下 TFS 的自定义代码分析签入策略

http://weblogs.asp.net/uruit/archive/2009/03/17/writing-custom-rules-for-tfs-2008-code-analysis-check-in-policy.aspx

于 2010-02-25T21:23:53.897 回答
0

.NET 框架希望通过使用 ! 修饰符。

public void MyMethod(!string cannotBeNull)

但是很遗憾,我们没有编译时检查。最好的办法是尽量减少外部调用者传递空值的次数,然后对面向公众的方法执行空检查:

public class ExternalFacing
{
  public void MyMethod(string arg)
  {
     if (String.IsNullOrEmpty(arg))
        throw new ArgumentNullException(arg);

     implementationDependency.DoSomething(arg);
   }
}

internal class InternalClass
{
    public void DoSomething(string arg)
    {
         // shouldn't have to enforce null here.
    }
}

然后将适当的单元测试应用于 External 类以预期 ArgumentNullExceptions。

于 2010-02-25T21:24:43.200 回答