分层架构的基本TDD方法

时间:2013-07-08 09:14:59

标签: asp.net-mvc asp.net-mvc-4 tdd

我是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时再次测试。

应该怎么做?

3 个答案:

答案 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