编程&单元测试最佳实践

时间:2011-10-03 16:15:41

标签: c# unit-testing tdd

我遇到的情况是我不太确定如何接近。

我们正在努力让我们的单元测试代码覆盖率达到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,是这有一个商业规则吗?“。

此致

詹姆斯

4 个答案:

答案 0 :(得分:5)

您仍然可以获得100%的代码覆盖率。考虑以下编译好的行:

QuarterFactory.CreateQuarter((IntervalType)0);

因此,这也回答了第二个问题。如果返回UnpaidBreakQuarter,您可能会收到非常令人困惑的结果。

简而言之:

  1. 保持默认的单元测试,如果通过则抛出异常 意外的事情(如上面一行)
  2. 不要这样做。如果有人没有说明他们想要这个, 他们不希望它被退回
  3. 你甚至可以通过这样做来引发异常:

    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