2008-09-19 46 views
2

我有以下情形:方法呼叫转移的单元测试策略是什么?

 
public class CarManager 
{ 
    .. 

    public long AddCar(Car car) 
    { 
     try 
     { 
     string username = _authorizationManager.GetUsername(); 
     ... 
     long id = _carAccessor.AddCar(username, car.Id, car.Name, ....); 
     if(id == 0) 
     { 
      throw new Exception("Car was not added"); 
     } 
     return id; 
     } catch (Exception ex) { 
     throw new AddCarException(ex); 
     } 
    } 

    public List AddCars(List cars) 
    { 
    List ids = new List(); 
    foreach(Car car in cars) 
    { 
     ids.Add(AddCar(car)); 
    } 
    return ids; 
    } 
} 

我嘲笑了_reportAccessor,_authorizationManager等

现在我想单元测试的CarManager类。 我应该有AddCar()多次试验,如

 
AddCarTest() 
AddCarTestAuthorizationManagerException() 
AddCarTestCarAccessorNoId() 
AddCarTestCarAccessorException() 

对于AddCars()我应该重复以前的所有测试,AddCars()调用AddCar() - 这似乎是重复自己?我可能不应该从AddCars()调用AddCar()? < p />

请帮忙。

+0

代码没有完全显示试图修复 – Xerx 2008-09-19 11:19:07

回答

1

单元测试应该只关注正在测试的相应类。应该模拟不同类型的所有属性。

假设您有一个使用某种数据访问对象(例如CarPlatesDAO)的类(CarRegistry),该对象从关系数据库中加载/存储车牌号码。

当您测试CarRegistry时,您不应该关心CarPlateDAO是否正确执行;由于我们的DAO有它自己的单元测试。

您只要创建模拟行为像DAO并根据预期的行为返回正确或错误的值。你将这个模拟DAO插入到你的CarRegistry中,只测试目标类而不关心所有聚合类是否为“绿色”。

模拟允许分离可测试类并更好地关注特定功能。

2

这里有两个问题:

  • 单元测试应该比测试方法一次一个多。他们应该被设计来证明你的班级可以完成它与系统其他部分整合时所设计的工作。所以你应该嘲笑这些依赖关系,然后为你实际使用类的每种方式写一个测试。对于您编写的每个(非平凡)类,都会涉及以特定模式调用客户端代码方法的方案。
  • AddCars调用AddCar没有任何问题。您应该重复错误处理测试,但仅限于其用途。单元测试的非官方规则之一是'测试到无聊'或者(正如我想的那样)'测试直到恐惧消失'。否则,你会永远写测试。所以如果你确信测试不会增加任何价值,那么他们就不写。你当然可能是错的,在这种情况下,你可以稍后再回来并添加它。你不必首次完成一个完美的测试,只需要一个坚实的基础,你可以更好地理解你的课程。需要做的。
+0

+1为实用的测试方法。另外,不从AddCars调用AddCar会违反DRY原则。 – 2009-01-29 14:13:55

1

单元测试AddCar类时,创建将执行每个代码路径的测试。如果_authorizationManager.GetUsername()可以抛出一个异常,那么在你的这个对象的模拟会抛出的地方创建一个测试。 BTW:不要抛出或捕获Exception的实例,但派生一个有意义的Exception类。

对于AddCars方法,您绝对应该调用AddCar。但是你可能会考虑让AddCar虚拟并重写它,只是为了测试它是否在列表中的所有车辆上被调用。

有时您必须更改可测试性的类设计。

1

编写可以探索方法中每种可能场景的测试都是很好的做法。这就是我在我的项目中进行单元测试的方式。像AddCarTestAuthorizationManagerException(),AddCarTestCarAccessorNoId()AddCarTestCarAccessorException()这样的测试可以让你考虑代码可能出现故障的所有不同方式,从而导致我发现一种我可能会错过的方法的新种类故障,并改进该类的整体设计。

在情状AddCars()调用AddCar()我会嘲笑AddCar()方法和计数的时候,它通过AddCars()拨通了电话。我使用的嘲讽图书馆允许我创建CarManager的模拟,仅模拟AddCar()方法,但不模拟AddCars()。然后你的单元测试可以设置它预计多少次AddCar()被称为你会知道从车在通过列表的大小。

+0

对于模拟方法AddCar,您是否会返回所有不同类型的异常以在AddCar中测试这些异常,或者您认为这是多余的,因为它在AddCar测试中进行了测试? – Xerx 2008-09-19 12:55:50

1

我应该有多个试验 AddCar()如

AddCarTest() AddCarTestAuthorizationManagerException() AddCarTestCarAccessorNoId() AddCarTestCarAccessorException()

绝对!这告诉你有价值的信息

对于AddCars()我应该重复以前的所有测试,AddCars()调用AddCar() - 它似乎像 重复自己?我可能不应该从AddCars()调用AddCar()?

从AddCars调用AddCar是一个好主意,它避免了违反DRY原则。同样,你应该重复测试。想想这样 - 你已经为AddCar写了测试,所以当测试AddCards时,你可以假设AddCar做的是。

让我们这样说 - 想象一下AddCar是在一个不同的类。您将不知道授权经理。测试AddCars 没有了解AddCar必须做什么。

对于AddCars,您需要测试所有正常的边界条件(是否有空列表工作等)。您可能不需要测试AddCar抛出异常的情况,因为您并不试图捕获它在AddCars中。

相关问题