C# C代码覆盖率可以';t在自定义断言失败的情况下达到所需的返回
我有一个自定义断言,它总是在其中抛出一个异常,但它被用于需要返回值的C#函数中。在下面的示例中,CustomAssert.Fail()总是抛出异常,因此“returnnull”永远不会执行。代码覆盖率将其标记为未经测试,我想解决这个问题C# C代码覆盖率可以';t在自定义断言失败的情况下达到所需的返回,c#,code-coverage,assert,C#,Code Coverage,Assert,我有一个自定义断言,它总是在其中抛出一个异常,但它被用于需要返回值的C#函数中。在下面的示例中,CustomAssert.Fail()总是抛出异常,因此“returnnull”永远不会执行。代码覆盖率将其标记为未经测试,我想解决这个问题 public string GetSomething() { CustomAssert.Fail(); return null; } 我曾经考虑过重构CustomAssert.Fail()以返回null对象并执行类似的操作,但这似乎有点太老土了
public string GetSomething()
{
CustomAssert.Fail();
return null;
}
我曾经考虑过重构CustomAssert.Fail()以返回null对象并执行类似的操作,但这似乎有点太老土了。有没有其他方法来实现这一点,或者我必须牺牲代码覆盖率
public string GetSomething()
{
return CustomAssert.Fail() as string;
}
首先,我不认为代码覆盖率是测试中最重要的度量。这是一个完美的例子,很明显,一切都可能经过完美的测试,但仍然无法得到100%的覆盖率。在这种情况下,我会接受没有全面保险的情况 也就是说,解决这个问题的一种方法是重构
CustomAssert.Fail()
以返回异常,然后简单地编写:
public string GetSomething()
{
throw CustomAssert.Fail();
}
缺点?您的CustomAssert
将有不一致的行为,如果可能,应该避免这种行为。正如您在注释中所说的,由于明显的原因,条件断言不能返回异常,因此您将有CustomAssert.IsNotNull(…)
不返回任何内容,并且在断言失败时抛出,而CustomAssert.Fail()
将返回必须由使用者显式抛出的异常。这个解决方案似乎有点恶心
稍微改善这种不便的一种方法是通过以下方式重构CustomAssert
:
public static class CustomAssert
{
public static void IsNotNull<T>(this T target)
{
if (ReferenceEquals(target, null)) throw new ArgumentNullException();
}
public static void IsTrue<T>(this T target, Predicate<T> validator)
{
if (!validator(target)) throw new ArgumentException();
}
public static void IsInRange<T, Q>(this T target, Q inclusiveLowerBound, Q exclusiveUpperBound) where T: IComparable<Q>
{
...
}
//etc.
public static T Fail<T>() where T :Exception, new()
{
return new T();
}
}
以上所说的,我会认真考虑改变<代码> CustomAssert < /COD>的名称。代码>断言
对大多数程序员来说都有一个相当明确的含义,它可能会引起误解。也许类似于首先,我不认为代码覆盖率是测试中最重要的度量。这是一个完美的例子,很明显,一切都可能经过完美的测试,但仍然无法得到100%的覆盖率。在这种情况下,我会接受没有全面保险的情况
也就是说,解决这个问题的一种方法是重构CustomAssert.Fail()
以返回异常,然后简单地编写:
public string GetSomething()
{
throw CustomAssert.Fail();
}
缺点?您的CustomAssert
将有不一致的行为,如果可能,应该避免这种行为。正如您在注释中所说的,由于明显的原因,条件断言不能返回异常,因此您将有CustomAssert.IsNotNull(…)
不返回任何内容,并且在断言失败时抛出,而CustomAssert.Fail()
将返回必须由使用者显式抛出的异常。这个解决方案似乎有点恶心
稍微改善这种不便的一种方法是通过以下方式重构CustomAssert
:
public static class CustomAssert
{
public static void IsNotNull<T>(this T target)
{
if (ReferenceEquals(target, null)) throw new ArgumentNullException();
}
public static void IsTrue<T>(this T target, Predicate<T> validator)
{
if (!validator(target)) throw new ArgumentException();
}
public static void IsInRange<T, Q>(this T target, Q inclusiveLowerBound, Q exclusiveUpperBound) where T: IComparable<Q>
{
...
}
//etc.
public static T Fail<T>() where T :Exception, new()
{
return new T();
}
}
以上所说的,我会认真考虑改变<代码> CustomAssert < /COD>的名称。代码>断言
对大多数程序员来说都有一个相当明确的含义,它可能会引起误解。也许类似于CustomValidator
的东西会更好。如果函数总是因为断言而失败,那么为什么不将其标记为过时呢?如果它只是一个特定的代码路径,为什么不简单地抛出一个NotSupportedException
或类似的函数呢?这个函数只是使用它的许多地方的一个例子。抛出异常就是这样做的,但是这个CustomAssert帮助器可以帮助进行许多相关的调用。查看Microsoft的Assert类:我不明白。正如问题中所描述的,您的问题是您的测试用例没有返回,因为断言总是失败。如果在某些条件下断言不能失败,那么测试就不能充分覆盖所有可能的执行路径,因为您永远不会到达return语句。另一方面,如果这个特定的代码路径必须总是失败,那么只需抛出一个异常,而不断言或返回。我看不到第三种选择。你没有牺牲代码覆盖率,你写的代码不能100%覆盖。如果你在一个要求100%覆盖率的地方,你会花更多的时间重构测试等代码更改,而不是专注于具有真正业务价值的代码。一些代码覆盖率工具能够将类/方法标记为排除在覆盖率之外,因为这类场景的原因;很明显,它可能会被懒惰的人滥用,但这就是为什么我们要进行代码审查之类的工作来保持每个人的诚实。@在这两者之间,它总是会失败的。CustomAssert.Fail的目的是在代码库中的许多地方使用它和类似的断言时生成一个统一的异常。唯一的问题是代码覆盖率工具不理解CustomAssert.Fail与引发异常相同。例如,该方法上的属性可以告诉代码覆盖率工具它总是抛出异常,因此将代码覆盖率标记为完成。显然,不存在这样的属性。问题中的第二个例子可能是唯一的选择。如果函数总是因为断言而失败,那么为什么不将其标记为过时呢?如果它只是一个特定的代码路径,为什么不简单地抛出一个NotSupportedException
或类似的函数呢?这个函数只是使用它的许多地方的一个例子。抛出异常就是这样做的,但是这个CustomAssert帮助器可以帮助进行许多相关的调用。查看Microsoft的Assert类:我不明白。正如问题中所描述的,您的问题是您的测试用例没有返回,因为断言总是失败。如果在某些条件下断言不能失败,那么测试就不能充分覆盖所有可能的执行路径,因为您永远不会到达return语句。另一方面,如果这个粒子