以下是我开始遇到的问题:
>我最终编写了应用程序代码,以使单元测试成为可能。我的意思不是很好,因为我的代码被破坏,我必须修复它,以便单元测试通过。我的意思是将数据库抽象为模拟数据库是不可能的,因为使用linq进行数据检索(使用通用存储库模式)。
原因是使用linq-> sql或linq->实体,您可以通过执行以下操作来加入:
var objs = select p from _container.Projects select p.Objects;
但是,如果您嘲笑数据库层,为了让该linq通过单元测试,您必须将linq更改为
var objs = select p from _container.Projects join o in _container.Objects on o.ProjectId equals p.Id select o;
这不仅意味着您正在更改应用程序逻辑,以便您可以对其进行单元测试,但是您仅仅为了实现可测试性而使代码效率降低,并且使用ORM摆脱了很多优势。 。
此外,由于我的模型的很多ID都是数据库生成的,所以我证明必须编写额外的代码来处理非数据库测试,因为ID不会被生成,我还必须处理这些单元测试通过的情况,但它们永远不会发生在真实情况下。
因此,我最终抛出了我的数据库单元测试。
只要我返回观点,写控制器的单元测试就很容易。然而,我的应用程序的主要部分(以及最受益于单元测试的)是一个复杂的ajax Web应用程序。由于各种原因,我决定将应用程序从返回的视图更改为使用我需要的数据返回JSON。发生这种情况之后,我的单元测试变得非常痛苦,因为我没有找到任何好的方法来编写单元测试用于非平凡的json。
在捣毁我的头,浪费了大量的时间,试图找到一个很好的方法来单元测试JSON,我放弃了并删除了我所有的控制器单元测试(所有控制器的操作都集中在这个应用程序的这一部分)。
>所以最后我离开了测试服务层(BLL)。现在我正在使用EF4,但是我也遇到linq-> sql这个问题。我选择了做EF4模型的第一种方式,因为对我来说,这样做是有道理的(定义我的业务对象,让框架弄清楚如何将它转换成sql后端)。这一开始很好,但现在由于关系而变得笨重。
例如说我有Project,User和Object实体。一个对象必须与项目相关联,并且项目必须与用户关联。这不仅仅是一个数据库特定的规则,这些也是我的业务规则。但是,我想做一个单元测试,我可以保存一个对象(一个简单的例子)。我现在必须做以下代码,以确保保存工作:
User usr = new User { Name = "Me" }; _userService.SaveUser(usr); Project prj = new Project { Name = "Test Project",Owner = usr }; _projectService.SaveProject(prj); Object obj = new Object { Name = "Test Object" }; _objectService.SaveObject(obj); // Perform verifications
有许多问题需要做所有这些只是为了执行一个单元测试。这有几个问题。
>对于初学者,如果我添加一个新的依赖项,例如所有的项目都必须属于一个类别,我必须进入每个引用一个项目的单个单元测试,添加代码来保存类别,然后添加代码来添加类别到项目。这可能是一个非常简单的业务逻辑变革的巨大努力,但几乎没有一个单元测试我将修改这个要求实际上是测试该功能/要求。
>如果我然后添加验证到我的SaveProject方法,所以项目不能保存,除非他们有一个至少5个字符的名称,然后我必须通过每个对象和项目单元测试,以确保新的要求不任何不相关的单元测试失败。
>如果UserService.SaveUser()方法中存在问题,它将导致所有项目和对象单元测试失败,并且原因不会立即引起注意,而无需挖掘异常。
因此,我已经从我的项目中删除了所有服务层单元测试。
我可以继续,但到目前为止,我没有看到任何方式进行单元测试来实际帮助我,而不是让我的方式。我可以看到具体的情况,我可以,也可能会实施单元测试,例如确保我的数据验证方法正常工作,但这些情况是很少的。我的一些问题可能会被缓解,但不能在我的应用程序中添加额外的层次,从而使得更多的故障点就可以进行单元测试。
因此,我的代码中没有单元测试。幸运的是,我大量使用源代码管理,所以我可以让他们回来,如果我需要,但我只是没有看到这一点。
互联网上的任何地方,我看到人们谈论TDD单元测试是多么的好,我不只是在讨论狂热的人。解散TDD /单元测试的少数人提供了不利的论据,声称他们通过IDE进行更有效的调试,或者他们的编码技术令人惊奇,他们不需要它。我认识到这两个论点都是完全的公牛,特别是对于需要由多个开发人员维护的项目,但对TDD的任何有效的反驳似乎都是很少的。
所以这个帖子的要点是问,我只是不了解如何使用TDD和自动单元测试?
解决方法
最后在ASP.NET MVC中进行单元测试可能是一个痛苦,没有妥善分离关注和抽象,并使用像MVCContrib.TestHelper这样的嘲笑框架和框架可以使您的生活更轻松。
Here’s a preview您的控制器单元测试可能如何。
更新:
作为对评论的回应,我认为编程是一项具体任务,很难给出如何单元测试我的复杂业务应用程序的最终答案。为了能够测试复杂的应用程序,层之间的耦合应尽可能弱,这可以通过接口和抽象类来实现。我同意,在复杂的应用中实现这样一个薄弱的耦合并不是一件小事。
我可以给你一个建议:如果整个TDD的概念很难理解,你没有看到没有好处,那么这是可以的。没有人可以证明TDD在所有情况下都是有益的。只需尝试设计您的应用程序,使每个课程都有一个责任。如果发现自己在同一个类中验证输入,sql数据访问和异常处理,那么你做错了。一旦实现了这种分离,您将看到单元测试变得更加容易,甚至可以在单元测试驱动您的开发阶段进行调试:-)
单元测试JsonResult与MvcContrib.TestHelper是一个具体的问题,我给了一个具体的答案:
public class MyModel { public string MyProperty { get; set; } } public class HomeController : Controller { public ActionResult Index() { return Json(new MyModel { MyProperty = "value" }); } }
和测试:
[TestMethod] public void HomeController_Index_Action_Should_Return_Json_Representation_Of_MyModel() { // arrange var sut = new HomeController(); // act var actual = sut.Index(); // assert actual .AssertResultIs<JsonResult>() .Data .ShouldBe<MyModel>("") .MyProperty .ShouldBe("value"); }