我遇到的情况是我不太确定如何接近。
我们正在努力让我们的单元测试代码覆盖率达到100%。
我一直在尝试采用TDD方法进行开发,编写测试,通过测试,编写失败的测试,添加更多代码以使其通过等等。
在这样做时,我发现我写了一个这样的类:
public enum IntervalType : int
{
Shift = 1,
PaidBreak = 2,
UnpaidBreak = 3
}
public static class QuarterFactory
{
public static IQuarter CreateQuarter(IntervalType intervalType)
{
switch (intervalType)
{
case IntervalType.Shift:
return new ShiftQuarter();
default:
throw new ArgumentException(String.Format("Unable to create a Quarter based on an IntervalType of: {0}", intervalType));
}
}
}
随着编码工作的进展,工厂扩展到:
public static class QuarterFactory
{
public static IQuarter CreateQuarter(IntervalType intervalType)
{
switch (intervalType)
{
case IntervalType.Shift:
return new ShiftQuarter();
case IntervalType.PaidBreak:
return new PaidBreakQuarter();
case IntervalType.UnpaidBreak:
return new UnpaidBreakQuarter();
default:
throw new ArgumentException(String.Format("Unable to create a Quarter based on an IntervalType of: {0}", intervalType));
}
}
}
我问的第一个问题是:
既然工厂已经完成了枚举,我是否为了代码覆盖而删除了默认异常,或者如果有人在枚举中添加新类型并忘记修改工厂,我是否将异常作为默认值保留在那里?
我要问的第二个问题是:
如果我决定删除异常并将类型默认为 UnpaidBreakQuarter - 默认情况下IQrosser返回到UnpaidBreakQuarter是否有意义,或者这会引发“为什么默认为UnpaidBreakQuarter,是这有一个商业规则吗?“。
此致
詹姆斯
答案 0 :(得分:5)
您仍然可以获得100%的代码覆盖率。考虑以下编译好的行:
QuarterFactory.CreateQuarter((IntervalType)0);
因此,这也回答了第二个问题。如果返回UnpaidBreakQuarter
,您可能会收到非常令人困惑的结果。
简而言之:
你甚至可以通过这样做来引发异常:
QuarterFactory.CreateQuarter(0);
答案 1 :(得分:2)
我认为你应该保留默认块,这是一个很好的做法,特别是对于你已经提到的情况,即如果有人在将来修改代码时添加一个新的IntervalType。
第二个问题的答案因此来了:)顺便说一句,使用默认值为指定值,因为“我知道剩下的唯一值是”非常可怕,默认值完全是针对异常或意外情况,或者至多是最常见的(例如:第一个没有,第二个没有,好的,所以 ANY 其他情况应该是这个值。)
答案 2 :(得分:1)
我认为您应该以100%的代码覆盖率为代价来保留默认值,除非确实有针对此的业务规则并且已记录在案。如果你选择保留它,当有人在枚举中添加另一个值时,会抛出一个异常作为“提醒”,在switch语句中添加大小写,我认为这是好的。
答案 3 :(得分:0)
你知道这种开关/枚举组合通常是代码味道吗? http://c2.com/cgi/wiki?SwitchStatementsSmell
您可以重构使用多态:这将保持100%的覆盖率,允许轻松添加新案例,并且不需要默认值,因为编译器会阻止它。
在这种情况下,两种最常见的重构是“用类替换类型代码”和更具体的“用策略替换类型代码”。另外,“用多态性替换条件”当然值得一看。 http://refactoring.com/catalog/replaceConditionalWithPolymorphism.html