我正在开展一个大型项目,即使有1000次自动测试和100%代码覆盖率,我们也会得到一些荒谬的错误。我们得到的大约95%的错误是NullReferenceExceptions。
有没有办法在编译时强制执行空值检查?
除此之外,有没有办法在单元测试中自动执行空值检查而不必自己编写空案例测试?
答案 0 :(得分:18)
你应该研究Code Contracts。静态检查器仅适用于高端VS版本,但这基本上就是你所追求的。
网上有大量资源,<plug>
您还可以阅读第二版C#深度代码合约章节的预发布版本 - download chapter 15 for free。 </plug>
(关于代码合同的最新和最大版本,该章略有过时,但没有什么大的。)
答案 1 :(得分:4)
100%的代码覆盖率毫无意义。
这是一种虚假的安全感。
你唯一测量的是你正在执行所有代码行。
不
例如,如果您处理火灾的程序包含一步“跑出大楼”,那么即使在100%的情况下发生这种情况,也许更好的程序是“提醒消防部门,试着阻止火灾,如果其他所有方法都失败了就会用完“。
C#中没有任何内容可以帮助您解决这个问题,而无需您专门进行并添加代码,代码合同(.NET 4.0)或特定的IF语句(&lt; 4.0)。
答案 2 :(得分:1)
这不是技术解决方案,而是社交方案。在外部代码(另一种方法调用等)以任何方式修改引用类型时,只需在您的环境中使其无法访问引用类型而不检查null。单元测试不能取代良好的老式代码审查。
答案 3 :(得分:1)
有没有办法在编译时强制执行空值检查?
不。编译器无法确定运行时引用变量是否指向null。
排除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;
答案 4 :(得分:1)
1)我认为,Resharper可以建议您检查代码中的一些关键位置。 例如,它建议添加[null引用检查代码]并在允许时添加它。
试试吧。如果您需要,它会增加您的体验。
2)在开发应用程序的早期阶段,在代码中使用“Fail Fast”模式(或断言,断言)
答案 5 :(得分:1)
防御性编程只能让你到目前为止......也许只是更好地捕捉异常并像其他任何一样处理它。
答案 6 :(得分:0)
这些都不可能与C#3一起使用。你必须使用像Spec#这样的东西...我认为C#4可能内置了一些,但我不确定。
答案 7 :(得分:0)
在编译时不能进行空检查,因为在编译时对象只是类型,并且仅在运行时将类型转换为具有特定值的实例...此处为null。
答案 8 :(得分:0)
也许你应该看看TFS的自定义代码分析签到政策
答案 9 :(得分:0)
我可能错了,但我认为FxCop有一条规则建议您在代码中添加空引用检查。您可以尝试通过该工具运行程序集,看看它有什么用。
答案 10 :(得分:0)
查看Gendarme,它可以在测试后与您的测试一起运行(如果您愿意,可以在它们之前运行)并且有一些与null
检查相关的规则。你也可以轻而易举地写自己的。
答案 11 :(得分:0)
C#8引入了Non-nullable reference types。
.Net Core项目可以修改为:
<LangVersion>8.0</LangVersion>
<NullableContextOptions>enable</NullableContextOptions>
编译器将能够区分
string
和string?
NonNullableClass
和NullableClass?
答案 12 :(得分:-1)
.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。