我是TDD的新手。我是第一次这样做。几乎没有什么混淆。看看下面的MVC示例:
CarApiController: GetCar, GetCars, PostCar, PutCar, DeleteCar
CarBLL(静态类): GetCar, GetCars, PostCar, PutCar, DeleteCar
CarDAL(静态类): SelectCar, SelectCars, InsertCar, UpdateCar, DeleteCar
在CarApiController中使用GetCars获取汽车列表,调用堆栈将是: CarApiController.GetCars() - > CarBLL.GetCars() - > CarDAL.SelectCars()
我应该只为CarApiController编写测试吗?或者我应该为所有三层写作?如果我为所有三层写入,CarDAL将被测试三次,一次用于自己的测试,然后我测试CarBLL和CarApiController。类似地,CarBLL将进行一次测试以进行自己的测试,并且在测试CarApiController时再次测试。
应该怎么做?
答案 0 :(得分:4)
如果你想采用TDD方式并且你真的想确保代码的可测试性,你必须摆脱你的static
类。另一点是,如果你要去TDD,你应该开始编写测试并让设计出现,而在这里你已经对你想要的设计有了一个坚实的想法...
正如您自己指出的那样,DAL将以这种方式进行三次测试,但这不是最糟糕的部分。最糟糕的是,您无法单独测试ApiController或BLL,这意味着如果测试中出现问题,您将无法知道哪个类失败并且无法实现单元测试的目的:快速查明失败的原因。
我会做的是这样的事情:
ICarDAL (interface) -> SelectCar, SelectCars, InsertCar, UpdateCar, DeleteCar
CarDAL将实现上述界面。
ICarBLL (interface) -> GetCar, GetCars, PostCar, PutCar, DeleteCar
让我们掩饰BLL镜像Api方法的事实。在我的想法中,BLL应该独立于使用层提供逻辑,所以也许方法如:GetCars,AddCar,EditCar,CreateCar ...可能只是名称不同但即使这很重要:这个BLL被用于桌面的那一刻例如,应用程序,然后PostCar和PutCar变得毫无意义。
CarBLL实现了上述功能。由于CalBLL使用DAL,因此其构造函数将如下所示:
public CarBLL(ICarDAL dal)
{
this.dal = dal;
}
对于控制器:
CarApiController -> GetCar, GetCars, PostCar, PutCar, DeleteCar
CarApiController将有一个类似的构造函数:
public CarApiController(ICarBLL bll)
{
this.bll = bll;
}
调用堆栈保持不变,但现在您的代码已解耦。请注意,要在ApiController中使用参数化构造函数,您需要在应用程序中注册某种IoC容器。我过去使用Unity非常满意。
现在我们可以跳舞了。我们的测试看起来像这样:
控制器测试:
public void test_that_this_works()
{
ICarBLL mock = new FakeCarBLL();
var controller = new CarApiController(mock);
Assert.That(controller.GetCars.Count(), Is.EqualTo(1));
}
通过上述内容,您可以编写一个BLL接口的伪实现,它始终返回相同的结果,您可以检查控制器中的操作是否正常。 BLL测试看起来很相似,但你会使用DAL的假实现来模拟来自数据库的一组结果,并且可能验证Save和Select方法被称为正确的次数(在这种情况下我会建议一个模拟库,例如RhinoMocks)
很抱歉很长的答案,但这是一个非常复杂和广泛的主题...祝你好运和编码愉快! :)
答案 1 :(得分:0)
是的,您测试所有图层。你可以独立测试它们。
您需要研究TDD的概念。在TDD中,您可以测试所有内容,并在编写生产代码之前和期间编写测试。
你需要研究的另一件事是嘲笑。当您测试一个类时,您使用模拟/存根(有些称为伪造)来输入,而不是使用您在生产代码中使用的实际类。当您测试CarApiController
时,应该模拟所有输入,因此您可以单独测试该类。这样,您只测试一个类和一个类。
答案 2 :(得分:-1)
最好只覆盖CarBLL。
当然你可以覆盖所有图层。但是你应该尝试保持你的控制器薄和BLL脂肪。如果您发现控制器变大,则应考虑将该逻辑移至BLL。
我想说所有的BLL类都应该用单元测试来覆盖。使用单元测试覆盖所有层总是好的,因为这将在重构代码时帮助您,但是我已经看到一些情况,当书面单元测试只是测试框架而这样的测试只是浪费时间...... / p>
想要注意的是,从您在问题中说明的架构示例中,如果您要查看“通用控制器”和“Generic Repository pattern”将会很好。
这是一个LINK to an example of a generic controller代码并不完美,但它为您提供了一些如何根据需要构建通用控制器的技巧。
这是一篇很好的文章,关于你不应该测试控制器的原因:http://www.codeproject.com/Articles/607396/Youplusshouldplusunitplustestplusyourpluscontrolle