首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >我是不是不理解测试驱动开发单元测试(Asp.Net MVC项目)?

我是不是不理解测试驱动开发单元测试(Asp.Net MVC项目)?
EN

Stack Overflow用户
提问于 2010-05-20 01:13:41
回答 3查看 1.9K关注 0票数 16

我正在尝试弄清楚如何正确有效地对我的Asp.net MVC项目进行单元测试。当我开始这个项目时,我买了project,通过这本书,我了解了ASP.Net和单元测试。在看过这些例子后,以及我在目前的公司做QA软件工程师的事实,我对TDD看起来有多棒感到惊讶。因此,我开始着手我的项目,开始为我的数据库层、业务层和控制器编写单元测试。在实现之前,一切都经过了单元测试。起初我认为这很棒,但后来事情开始走下坡路。

以下是我开始遇到的问题:

  • I最终编写了应用程序代码,以便能够执行单元测试。我的意思不是好的,因为我的代码坏了,我必须修复它,这样单元测试才能通过。我的意思是,将数据库抽象为模拟数据库是不可能的,因为使用linq进行数据检索(使用通用存储库模式).The原因是,使用linq->sql或linq->实体,您只需执行以下操作即可进行连接:

var objs = select p _container.Projects select p.Objects;

但是,如果您模拟数据库层,为了使linq通过单元测试,您必须将linq更改为

var objs = select p from _container.Projects join o in _container.Objects on o.ProjectId等于p.Id select o;

这不仅意味着你正在改变你的应用程序逻辑以便你可以对它进行单元测试,而且你正在为了可测试性而降低你的代码的效率,并且摆脱了在第一个place.Furthermore中使用ORM的许多优点,因为我的模型的许多I都是数据库生成的,我证明了必须编写额外的代码来处理非数据库测试,因为I从来没有生成过,我仍然必须处理这些情况才能让单元测试通过,然而它们永远不会在真实的场景中发生。

因此,我最终放弃了我的数据库单元测试。只要我返回视图,

  • 为控制器编写单元测试就很容易。但是,我的应用程序的主要部分(也是从单元测试中获益最多的部分)是一个复杂的ajax web应用程序。出于各种原因,我决定将应用程序从返回视图更改为返回包含所需数据的JSON。在这种情况发生后,我的单元测试变得非常痛苦,因为我还没有找到任何好的方法来为非平凡的json.After编写单元测试,这让我头疼,浪费了大量的时间试图找到一个好的方法来对JSON进行单元测试,我放弃并删除了所有的控制器单元测试(到目前为止,所有的控制器操作都集中在应用程序的这一部分)。

  • ,所以最后我只剩下测试服务层(BLL)了。现在我正在使用EF4,但是我在linq->sql上也遇到了这个问题。我选择了EF4模型优先的方法,因为对我来说,这样做是有意义的(定义我的业务对象,让框架找出如何将其转换为sql后端)。这在一开始是很好的,但现在变得很麻烦,因为例如我有ProjectUserObject实体。一个对象必须关联到一个项目,一个项目必须关联到一个用户。这不仅仅是特定于数据库的规则,这些也是我的业务规则。但是,假设我想做一个能够保存对象的单元测试(举个简单的例子)。我现在必须执行以下代码,以确保保存工作正常:

User usr =新建用户{ Name = "Me“};_userService.SaveUser( usr );Project prj =新建项目{ Name =”测试项目“,所有者=usr };_projectService.SaveProject(prj);Object obj =新建对象{ Name =”测试对象“};_objectService.SaveObject(obj);//进行验证

仅仅为了执行一次单元测试就必须执行所有这些操作,这会带来很多问题。这有几个问题。

代码语言:javascript
复制
- For starters, if I add a new dependency, such as all projects must belong to a category, I must go into EVERY single unit test that references a project, add code to save the category then add code to add the category to the project.  This can be a HUGE effort down the road for a very simple business logic change, and yet almost none of the unit tests I will be modifying for this requirement are actually meant to test that feature/requirement.
- If I then add verifications to my SaveProject method, so that projects cannot be saved unless they have a name with at least 5 characters, I then have to go through every Object and Project unit test to make sure that the new requirement doesn't make any unrelated unit tests fail.
- If there is an issue in the `UserService.SaveUser()` method it will cause all project, and object unit tests to fail and it the cause won't be immediately noticeable without having to dig through the exceptions.

因此,我已经从我的项目中删除了所有服务层单元测试。

我可以继续下去,但到目前为止,我还没有看到单元测试有任何方法可以真正帮助我,而不是妨碍我。我可以看到我可以实现单元测试的特定案例,例如确保我的数据验证方法正确工作,但这些案例很少。我的一些问题可能可以减轻,但不能不向我的应用程序添加额外的层,从而使更多的故障点,以便我可以单元测试。

因此,我的代码中没有留下单元测试。幸运的是,我大量使用源代码控制,所以如果我需要的话,我可以把它们拿回来,但我就是看不到这一点。

在互联网上到处都可以看到人们在谈论TDD单元测试有多棒,我不仅仅是在谈论那些狂热的人。少数对TDD/单元测试不屑一顾的人给出了糟糕的论据,声称他们通过IDE手动调试更有效,或者他们的编码技能令人惊叹,因为他们不需要它。我认识到这两个论点都是彻头彻尾的论据,特别是对于一个需要由多个开发人员维护的项目来说,但任何对TDD的有效反驳似乎都很少。

所以这篇文章的重点是要问,我是不是不理解如何使用TDD和自动单元测试?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-05-20 01:18:25

你可以看看我写的一个sample ASP.NET MVC 2.0 project structure。它提供了一些概念,可以帮助您开始对控制器、逻辑和数据库进行单元测试。就数据库测试而言,它不再是单元测试,而是集成测试。正如您将在我的示例中看到的那样,我使用的是NHibernate,它允许我轻松地切换到为每个测试夹具重新创建的示例SQLite数据库。

最后,在没有适当分离关注点和抽象的情况下,在ASP.NET MVC中进行单元测试可能会很痛苦,而使用模拟框架和MVCContrib.TestHelper等框架可以让您的工作更轻松。

控制器单元测试可能是什么样子的Here's a preview

更新:

作为对这些评论的回应,我认为编程是一项具体的任务,对于如何对复杂的业务应用程序进行单元测试,很难给出最终的答案。为了能够测试复杂的应用程序,各层之间的耦合应该尽可能弱,这可以通过接口和抽象类来实现。我同意,在复杂的应用程序中实现如此弱的耦合并不是一项微不足道的任务。

我可以给你一个建议:如果整个TDD概念很难理解,并且你看不到它有什么好处,那么这是可以的。没有人能证明TDD在所有情况下都是有益的。只需尝试以这样一种方式设计您的应用程序,即每个类都有一个单独的职责。如果您发现自己在同一个类中进行输入验证、SQL数据访问和异常处理,那么您就做错了。一旦实现了这种分离,您将看到单元测试变得更加容易,甚至可以达到单元测试驱动开发的阶段:-)

就使用MvcContrib.TestHelperJsonResult进行单元测试而言,这是一个具体的问题,我给出了一个具体的答案:

代码语言:javascript
复制
public class MyModel
{
    public string MyProperty { get; set; }
}

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return Json(new MyModel { MyProperty = "value" });
    }
}

测试:

代码语言:javascript
复制
[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");
}
票数 6
EN

Stack Overflow用户

发布于 2010-05-20 20:14:24

听起来问题不在于单元测试,而在于你的工具/平台。我有Java背景,所以我不必仅仅为了满足单元测试而重写查询。

测试Json是一件痛苦的事情,你知道吗。如果你不想测试它,那就不要;)测试并不是100%的覆盖率。它正在测试真正需要测试的东西。你更有可能在一个复杂的if表达式中得到一个bug,而不是将一些东西添加到一个map中,然后将其转换成json。

如果您测试是否正确创建了地图...json很有可能也是正确的。当然,它不会总是正确的,但是一旦你运行了它,它就会工作。或者不是。事情真的就这么简单。

不过,我可以对第三个问题提供一个真实的评论。你真的不想创建大量的对象图。但是有一些方法可以做到这一点。

创建一个名为ObjectMother的单例。有像ObjectMother.createProject()这样的方法。在内部,您可以创建虚拟项目实例。这样,12个测试可以使用此方法,然后您只需在一个位置更改它。记住,测试代码需要重构!

此外,您还可以研究一下dbUnit之类的东西。好吧,这就是它在Java世界里的名字。其想法是,在运行每个测试之前,它会将数据库置于已知状态。它会在你的测试的设置/拆卸过程中自动完成这项工作。这意味着您的测试代码可以立即开始测试。实际的虚拟测试数据在脚本或xml文件中。

我希望这能有所帮助。

票数 3
EN

Stack Overflow用户

发布于 2010-08-02 21:32:48

至于测试您的AJAXified视图,我建议您尝试一下像WatiN这样的测试框架。

有了这个,你可以做以下事情(来自他们的站点的例子)。

代码语言:javascript
复制
[Test]
public void SearchForWatiNOnGoogle()
{
 using (var browser = new IE("http://www.google.com"))
 {
  browser.TextField(Find.ByName("q")).TypeText("WatiN");
  browser.Button(Find.ByName("btnG")).Click();

  Assert.IsTrue(browser.ContainsText("WatiN"));
 }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2867798

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档