TDD实验1
2008-12-04 11:44 敏捷的水 阅读(2245) 评论(13) 编辑 收藏 举报用户故事:我们要找一个女朋友,这个女朋友要能够管理财务。
1. 先创建一个工程,引入NUnit,我们这里用这个做单元测试。
2. 设定,调试时启动Nunit
3. 写一个测试类
首先我们需要一个有一个能管财务女朋友。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
namespace FindGrilFriendTest
{
[TestFixture]
public class TestGrilFriend
{
[Test]
public void IsFinanceAbility()
{
GrilFriend myGril = new GrilFriend();
Assert.IsNotNull(myGril);
}
}
}
4.现在启动Debug
5. 我们发现这个都无法编译通过,因为没有GrilFriend类
6. 我们利用重构工具,生成GrilFriend类
namespace FindGrilFriendTest
{
public class GrilFriend
{
public GrilFriend()
{
throw new NotImplementedException();
}
}
[TestFixture]
public class TestGrilFriend
{
[Test]
public void IsFinanceAbility()
{
GrilFriend myGril = new GrilFriend();
Assert.IsNotNull(myGril);
}
}
}
我们把这个类提到一个单独的文件叫GrilFriend.cs, 运行测试
7. 为了让测试通过,我们去掉构造函数里的那句
using System;
namespace FindGrilFriendTest
{
public class GrilFriend
{
public GrilFriend()
{
}
}
}
测试通过,看到绿色,好爽
8. 先在我们测试grilFriend是否有财务能力。
using System;
using NUnit.Framework;
namespace FindGrilFriendTest
{
[TestFixture]
public class TestGrilFriend
{
[Test]
public void IsFinanceAbility()
{
GrilFriend myGril = new GrilFriend();
Assert.IsNotNull(myGril);
bool strongGrilFriend=myGril.IsFinanceAbility();
if (strongGrilFriend)
{
Console.Out.WriteLine("Yes,she is suit for my grilfriend");
}
}
}
}
using System;
namespace FindGrilFriendTest
{
public class GrilFriend
{
public GrilFriend()
{
}
internal bool IsFinanceAbility()
{
throw new NotImplementedException();
}
}
}
编译明显失败。修改为
internal bool IsFinanceAbility()
{
return true;
}
}
测试Pass,绿色,爽。
9. 现在我们的这个girlFriend不喜欢财务,所以我们现在加一个功能,就是这个girlFriend找个女佣来算帐。
internal bool IsFinanceAbility()
{
Servant myServant = new Servant();
if (myServant.CouldCalc())
{
return true;
}
else
{
return false;
}
}
10. 编译没法通过,因为这个Servant还没有创建,我们可以立即创建一个Servant类,加上CouldCalc方法,但问题是,这些都让我们自己加的话,我们要累死了,所以我们想让Servant这个类让另一个开发人员Bill来写,Bill说:“好,但是我用一天的时间”,哎,难道我们需要等一天?这时候我们想到了接口,于是我们修改代码
using System;
namespace FindGrilFriendTest
{
public class GrilFriend
{
public IServant myServant;
public GrilFriend()
{
}
internal bool IsFinanceAbility()
{
if (myServant.CouldCalc())
{
return true;
}
else
{
return false;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace FindGrilFriendTest
{
public interface IServant
{
bool CouldCalc();
}
}
这时候,我们的girlFriend需要测试这个仆人会不会计算,但我们如何如何判断,上面的方法无法判断,仆人不做任何工作,只要Return true,就骗过girlFriend了。现在我们改写这个测试方法为,如果我传一个数,他能把这个数乘以2,我们就认为他可以.
using System;
using System.Collections.Generic;
using System.Text;
namespace FindGrilFriendTest
{
public interface IServant
{
long CouldCalc(int i);
}
}
using System;
using NUnit.Framework;
namespace FindGrilFriendTest
{
[TestFixture]
public class TestGrilFriend
{
[Test]
public void IsFinanceAbility()
{
GrilFriend myGril = new GrilFriend();
Assert.IsNotNull(myGril);
Random r = new Random(1000);
int i = r.Next();
long strongGrilFriend=myGril.IsFinanceAbility(i);
if (strongGrilFriend==2*i)
{
Console.Out.WriteLine("Yes,she is suit for my grilfriend");
}
}
}
}
Test失败,修改grilFriend类
using System;
namespace FindGrilFriendTest
{
public class GrilFriend
{
public IServant myServant;
public GrilFriend()
{
}
internal long IsFinanceAbility(int i)
{
return myServant.CouldCalc(i);
}
}
}
测试,还是失败
看错误信息,是有对象没有实例化,我们Debug一下,发现 return myServant.CouldCalc(i)出错; myServant没有实例化,是因为Bill还没有开发具体类,但是现在把Bill叫回来,还是继续等待,看来都不是好方法,这个时候,我们有的人可能觉得我自己先写一个类来模拟一下,可是如果这样,当Bill完成后,我们还的需要改代码,这个时候,一个东西迅速出现在脑海里,那就是Mock
现在我们修改测试类
using System;
using NUnit.Framework;
using Rhino.Mocks;
namespace FindGrilFriendTest
{
[TestFixture]
public class TestGrilFriend
{
[Test]
public void IsFinanceAbility()
{
GrilFriend myGril = new GrilFriend();
Assert.IsNotNull(myGril);
Random r = new Random(1000);
int i = r.Next();
MockRepository mockRepository = new MockRepository();
IServant mockServant = mockRepository.CreateMock<IServant>();
Expect.Call(mockServant.CouldCalc(i)).Return(2 * i);
mockRepository.ReplayAll();
myGril.myServant = mockServant;
long strongGrilFriend=myGril.IsFinanceAbility(i);
mockRepository.VerifyAll();
if (strongGrilFriend==2*i)
{
Console.Out.WriteLine("Yes,she is suit for my grilfriend");
}
}
}
}
using System;
namespace FindGrilFriendTest
{
public class GrilFriend
{
public IServant myServant;
public GrilFriend()
{
}
public long IsFinanceAbility(int i)
{
if (myServant != null)
{
return myServant.CouldCalc(i);
}
else
{
return 0;
}
}
}
}
测试,哇,通过了。绿色,好爽.
至此,我们完成了我们的功能,找到一个适合自己的女朋友。Bill这个时候还在腐败呢。
总结:
这是我自己用TDD的方式第一次体验,当然我对TDD还不怎么了解,现在感觉是看到绿色很爽,写完代码有了测试代码了,而且过程中多次修正自己的设计。不好的地方是时间大大超过预期。如果哪位仁兄能够提供一些更好的TDD guideline,再次非常感谢。
问题:这里我们看到,找servant应该是girlFriend类自己的事,现在却需要我们传进去,可是内部如果实例化,我们又没法Mock,因为Mock只能写在测试代码里。这让我想到了IOC, 但是还没实验,下节我试试IOC能否解决。
本文写于:2008-12-03 23:50 王德水
扫码关注公众号,了解更多管理,见识,育儿等内容
出处:http://www.cnblogs.com/cnblogsfans
版权:本文版权归作者所有,转载需经作者同意。