一、要记住的一些东西
1. 首先要明确用户的需求,然后列出需求,首先写测试代码。(也就是先从用户这方调用功能)
2. 看到红灯,则明白需要写程序代码。即写功能代码。
3. 一直到绿灯,然后看是否需要重构。
4. 在重构过后,继续写测试代码,增加用户功能调用,然后重复上述过程,就是测试驱动开发的力量。
5. 测试代码比文档更具有说服力,不仅让用户让测试程序员更加明白你的类是如何使用的。
6. Kent Beck把TDD定义为以下两个简单的规则:1)除非你在自动测试中失败,否则一行代码也不要写;2)消除重复(包括测试代码在内)。
二、第一个基于TDD的程序
(1)需求:一个保存文章的类Article,用于我以后将会开发的Web项目中。此Article类包括功能如下:
1. 创建一个Article,IsDirty为false;
2. 修改Article的Title后,IsDirty为true;
3. 修改Article的Title后,要查看是否真的修改了Title的值;
4. 调用Article的Save后,IsDirty为false,可代表已将文章保存到数据库中。
其它的功能,以后的文章中会渐进地实现。
(2)编写测试代码(使用了VS2005中的测试项目)
ArticleTest
1
using System;
2
using System.Text;
3
using System.Collections.Generic;
4
using Microsoft.VisualStudio.TestTools.UnitTesting;
5![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
6
namespace FirstTDDProject
7![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
8![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
9
/// ArticleTest 的摘要说明
10
/// </summary>
11
[TestClass]
12
public class ArticleTest
13![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
14
15![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
16
public ArticleTest()
17![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
18
}
19![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
20![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
其他测试属性#region 其他测试属性
21
//
22
// 您可以在编写测试时使用下列其他属性:
23
//
24
// 在运行类中的第一个测试之前使用 ClassInitialize 运行代码
25
// [ClassInitialize()]
26
// public static void MyClassInitialize(TestContext testContext) { }
27
//
28
// 在类中的所有测试都已运行之后使用 ClassCleanup 运行代码
29
// [ClassCleanup()]
30
// public static void MyClassCleanup() { }
31
//
32
// 在运行每个测试之前使用 TestInitialize 运行代码
33
// [TestInitialize()]
34
// public void MyTestInitialize() { }
35
//
36
// 在运行每个测试之后使用 TestCleanup 运行代码
37
// [TestCleanup()]
38
// public void MyTestCleanup() { }
39
//
40
#endregion
41![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
42
protected Article _art;
43
[TestInitialize()]
44![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public void Initialize()
{
45
_art = new Article();
46
}
47![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
48
[TestMethod]
49
public void CheckIsDirty()
50![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
51
Assert.IsFalse(_art.IsDirty);
52
}
53![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
54
[TestMethod]
55
public void ChangeTitle()
56![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
57
_art.Title = "NewTitle";
58
Assert.IsTrue(_art.IsDirty, "After changing the Article.Title ,Article.IsDirty should be true.");
59
}
60![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
61
[TestMethod]
62
public void ChangeTitleVerify()
63![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
64
_art.Title = "The first TDD Application.";
65
Assert.AreEqual(_art.Title, "The first TDD Application.",
66
"After changing the Article.Title ,Article.Title should be 'The first TDD Application..' .");
67
}
68![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
69
[TestMethod]
70
public void SaveArticle()
71![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
72
_art.Title = "The first TDD Application.";
73
_art.Save();
74
Assert.IsFalse(_art.IsDirty, "After Saving the Article ,Article.IsDirty should be false.");
75
}
76
}
77
}
78
使用NUint编写的单元测试
ArticleTestWithNUnit
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
using NUnit.Framework;
5![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
6
namespace FirstTDDProject
7![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
8
[TestFixture]
9
public class ArticleTestWithNUnit
10![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
11
12
protected Article _art;
13
[SetUp]
14
public void Init()
15![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
16
_art = new Article();
17
}
18![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
19
[Test]
20
public void CheckIsDirty()
21![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
22
Assert.IsFalse(_art.IsDirty);
23
}
24![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
25
[Test]
26
public void ChangeTitle()
27![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
28
_art.Title = "NewTitle";
29
Assert.IsFalse(_art.IsDirty, "After changing the Article.Title ,Article.IsDirty should be true.");
30
}
31![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
32
[Test]
33
public void ChangeTitleVerify()
34![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
35
_art.Title = "The first TDD Application.";
36
Assert.AreEqual(_art.Title, "The first TDD Application.",
37
"After changing the Article.Title ,Article.Title should be 'The first TDD Application..' .");
38
}
39![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
40
[Test]
41
public void SaveArticle()
42![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
43
_art.Title = "The first TDD Application.";
44
_art.Save();
45
Assert.IsTrue(_art.IsDirty, "After Saving the Article ,Article.IsDirty should be false.");
46
}
47
}
48
}
49
根据测试代码一步步完善的Article代码
Article
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4![None.gif](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
5
namespace FirstTDDProject
6![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
7
public class Article
8![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
9
private bool _isDirty;
10
private string _title;
11
private string _body;
12![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
13
public string Body
14![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
15![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _body; }
16![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
set
{
17
_body = value;
18
_isDirty = true;
19
}
20
}
21![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
22
public string Title
23![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
24![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _title; }
25
set
26![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
27
_title = value;
28
_isDirty = true;
29
}
30
}
31![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
32
public bool IsDirty
33![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
34![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _isDirty; }
35
}
36![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
37![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
38
public Article()
39![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
40
_isDirty = false;
41
}
42![InBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
43
public void Save()
44![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
45
_isDirty = false;
46
}
47
}
48
}
49
本文参考了Visual Studio 2005 Team System的测试驱动开发。