我已经阅读了很多关于测试驱动开发(TDD)的内容,并且根据个人经验,我发现这些原则非常引人注目。
目前我正在为一个我参与的初创项目开发一个网站,我想尝试将TDD付诸实践。
所以......我在Visual Studio 2010中创建了一个空白解决方案,添加了一个ASP.NET MVC网站项目和一个测试项目。
我还为我的域对象添加了一个名为“Domain”的类库,以及一个测试项目。
现在我想知道从哪里开始。在我做任何事情之前,我应该写一个测试吗?问题是 - 我应该开始为域对象编写测试吗?如果是这样,我究竟应该测试什么,因为域对象还不存在?
或者我应该从网站项目开始并为此编写测试?如果是这样,我应该为什么编写测试?家庭控制器/指数行动?
答案 0 :(得分:11)
我通常首先为我即将开发的应用程序收集一组故事。从那里我生成一个域模型,通常在“纸上”。我组织了我将要实现的故事,并开始在数据库中为第一组故事创建域模型。
一旦我拥有了初始数据库,那么我使用ORM(在我的例子中是LINQ to SQL)将数据库表映射到一组初始类。我通常不会对生成的代码进行单元测试,所以这给了我相当多的代码作为开始的基础。然后我创建一个存根方法,它抛出一个未实现的异常,来实现我正在使用的第一个域类的一个特性。通常,我从验证逻辑开始。获得存根方法后,可以使用VS右键单击菜单为该方法创建一个或多个单元测试。那你就在路上。
一旦我完成了第一个故事的域对象,我就开始使用MVC方面。首先,我将为第一个视图创建视图模型。这一点通常只是一个空的容器类。然后我将创建视图并将其强烈键入视图模型。我将开始充实视图,根据视图的需要向视图模型添加属性。请注意,由于视图模型只是一个容器,因此通常不会与其关联的单元测试。然而,它将用于随后的控制器测试中。
一旦视图完成(或者至少我的初始概念已经完成),然后我为它创建存根控制器操作或操作,stub方法再次抛出一个未实现的异常。这足以让它编译并让我使用这些工具为它创建单元测试。我根据需要继续测试方法并确保它对给定的输入适当地起作用并产生适当的视图模型。如果该方法可以生成多个视图模型,即渲染多个视图,我可以迭代创建视图模型/视图/控制器代码的过程,直到故事或故事完成。
根据需要重复,直到你的故事集实施,并一路重构。
答案 1 :(得分:3)
在声明正在测试的类之前编写单元测试在C#等静态语言中似乎有点极端。所以你首先声明你的域类,抛出一些定义你将在这些域对象上执行的操作的接口,然后添加一个实现接口的类,让方法抛出NotImplementedException
。那时你可以为这个类写一个单元测试,因为所有类型都是已知的。您运行将失败的测试,然后您实现该方法并再次运行测试 - 它将通过。然后你可以重构和优化你的实现,你的单元测试仍然应该通过。
一旦你拥有了一个不错的域模型和数据访问层,你就可以使用你之前定义的接口(通过制作一个带有这个接口的构造函数)移动到你创建控制器的web项目。您可以通过使用模拟对象替换接口来为此控制器编写单元测试,以便您可以独立于数据访问代码测试控制器操作。
最重要的是:不要害怕添加类和接口。我见过人们写的巨大的方法同时执行多个事情,很难测试。尝试将不同的任务隔离到您可以轻松编写规范的方法中:您对不同的可能输入的期望输出。
答案 2 :(得分:2)
对于长篇答案,你应该采取这样的小步骤。
1) - 首先写一个失败的测试
[Test]
public void AddSameTag()
{
UserMovie userMovie = new UserMovie();
userMovie.AddTag("action", "dts", "dts");
Assert.AreEqual(2, userMovie.Tags.Count);
}
2) - 编写最简单的代码以通过测试。
public virtual void AddTag(params string[] tags)
{
foreach (var text in tags)
{
Tag tag =new Tag(text.Trim());
if (!movieTags.Contains(tag))
movieTags.Add(tag);
}
}
3) - 重构
。 对于ASP.NET MVC和TDD启动程序,您可以忽略Controller Test并关注Domain by TDD。
答案 3 :(得分:0)