继续我们的TDD,还是先看to-do list
检查输入是否合法
实现IRandomIntGenerator
实现IGameHistory
显示猜测纪录
检查输入是否合法
还是测试先行
[Test]
public void should_return_true_when_input_is_valid()
{
InputValidator validator = new InputValidator();
Assert.That(validator.Validate( " 1 2 3 4 " ), Is.True);
}
还是先写功能代码让编译通过,然后运行测试,红了,接着把功能代码写完让测试变绿
public void should_return_true_when_input_is_valid()
{
InputValidator validator = new InputValidator();
Assert.That(validator.Validate( " 1 2 3 4 " ), Is.True);
}
public
class
InputValidator
{
public bool Validate( string input)
{
return true ;
}
}
这里我只是简单的返回了true,第一,我现在的任务就是让测试通过,而返回true就已经满足条件了;第二因为我们还没写输入错误的测试,因此不需要先考虑错误的情况。
{
public bool Validate( string input)
{
return true ;
}
}
接下来写几个测试输入错误的测试,先写一个测试输入元素数量多于4个的测试,顺便把validator的构造提取到setup里
private
InputValidator validator;
[SetUp]
public void Setup()
{
validator = new InputValidator();
}
[Test]
public void should_return_false_when_input_has_more_numbers_than_four()
{
Assert.That(validator.Validate( " 1 2 3 4 5 " ), Is.False);
}
[SetUp]
public void Setup()
{
validator = new InputValidator();
}
[Test]
public void should_return_false_when_input_has_more_numbers_than_four()
{
Assert.That(validator.Validate( " 1 2 3 4 5 " ), Is.False);
}
public
bool
Validate(
string
input)
{
string [] numbers = input.Split( new []{ ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (numbers.Length > 4 )
{
return false ;
}
return true ;
}
再写一个输入元素少于4个的
{
string [] numbers = input.Split( new []{ ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (numbers.Length > 4 )
{
return false ;
}
return true ;
}
[Test]
public void should_return_false_when_input_has_less_numbers_than_four()
{
Assert.That(validator.Validate( " 1 2 3 " ), Is.False);
}
public
bool
Validate(
string
input)public void should_return_false_when_input_has_less_numbers_than_four()
{
Assert.That(validator.Validate( " 1 2 3 " ), Is.False);
}
{
string [] numbers = input.Split( new []{ ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (numbers.Length != 4 )
{
return false ;
}
return true ;
}
[Test]
public void should_return_false_when_input_contains_non_number()
{
Assert.That(validator.Validate( " 1 d 3 4 " ), Is.False);
}
public void should_return_false_when_input_contains_non_number()
{
Assert.That(validator.Validate( " 1 d 3 4 " ), Is.False);
}
public
bool
Validate(
string
input)
{
string [] numbers = input.Split( new [] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (numbers.Length != 4 )
{
return false ;
}
foreach (var num in numbers)
{
int result;
if ( ! int .TryParse(num, out result))
{
return false ;
}
}
return true ;
}
测试输入的数是否在0-9之间
{
string [] numbers = input.Split( new [] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (numbers.Length != 4 )
{
return false ;
}
foreach (var num in numbers)
{
int result;
if ( ! int .TryParse(num, out result))
{
return false ;
}
}
return true ;
}
[Test]
public void should_return_false_when_input_nunbers_is_not_between_zero_and_nine()
{
Assert.That(validator.Validate( " 1 2 10 -1 " ), Is.False);
}
public
bool
Validate(
string
input)public void should_return_false_when_input_nunbers_is_not_between_zero_and_nine()
{
Assert.That(validator.Validate( " 1 2 10 -1 " ), Is.False);
}
{
string [] numbers = input.Split( new [] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (numbers.Length != 4 )
{
return false ;
}
foreach (var num in numbers)
{
int result;
if ( ! int .TryParse(num, out result))
{
return false ;
}
if (result < 0 || result > 9 )
{
return false ;
}
}
return true ;
}
[Test]
public void should_return_false_when_input_contains_repeat_nunbers()
{
Assert.That(validator.Validate( " 1 1 2 3 " ), Is.False);
}
public void should_return_false_when_input_contains_repeat_nunbers()
{
Assert.That(validator.Validate( " 1 1 2 3 " ), Is.False);
}
写代码通过测试并重构


public class InputValidator
{
private const int InputLength = 4;
private const int MaxNum = 9;
private const int MinNum = 0;
public bool Validate(string input)
{
string[] numbers = input.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
return IsInputLengthCorrect(numbers)
&& IsInputAreAllInteger(numbers)
&& IsInputAreAllBetweenZeroAndNine(numbers)
&& IsUnique(numbers);
}
private static bool IsInputAreAllBetweenZeroAndNine(IEnumerable<string> numbers)
{
return numbers.All(numStr => Convert.ToInt32((string) numStr).IsBetween(MinNum, MaxNum));
}
private static bool IsInputLengthCorrect(ICollection<string> numbers)
{
bool correct = numbers.Count == InputLength;
return correct;
}
private static bool IsInputAreAllInteger(IEnumerable<string> numbers)
{
int num;
return numbers.All(number => int.TryParse(number, out num));
}
private static bool IsUnique(IEnumerable<string> numbers)
{
return numbers.Distinct().Count() == InputLength;
}
}
实现IGameHistory


[TestFixture]
public class TestGameHistory
{
[Test]
public void should_get_histories_in_order()
{
var history = new GameHistory();
history.Add(new[] {1, 2, 3, 4}, "0A0B");
history.Add(new[] {2, 3, 4, 5}, "0A2B");
history.Add(new[] {4, 5, 6, 7}, "1A2B");
var expectedResult = new StringBuilder();
expectedResult.AppendLine("1 2 3 4 : 0A0B");
expectedResult.AppendLine("2 3 4 5 : 0A2B");
expectedResult.AppendLine("4 5 6 7 : 1A2B");
Assert.That(history.GetAll(), Is.EqualTo(expectedResult.ToString()));
}
}


public class GameHistory : IGameHistory
{
private readonly List<string> histories = new List<string>();
#region IGameHistory Members
public void Add(int[] guess, string guessResult)
{
var oneHistory = new StringBuilder();
foreach (int num in guess)
{
oneHistory.AppendFormat("{0} ", num);
}
oneHistory.AppendFormat(": {0}", guessResult);
histories.Add(oneHistory.ToString());
}
public string GetAll()
{
var output = new StringBuilder();
foreach (string history in histories)
{
output.AppendLine(history);
}
return output.ToString();
}
#endregion
}
实现IRandomIntGenerator


public class RandomIntGenerator : IRandomIntGenerator
{
private readonly Random random;
public RandomIntGenerator()
{
random = new Random();
}
#region IRandomIntGenerator Members
public int Next()
{
return random.Next(0, 10);
}
#endregion
}
这里并没有再写测试了,一个原因是这个类比较简单,另一个原因是它的主要逻辑都委托给了标准库,而且Random很难测试。
Todo-list
随机生成答案
检查输入是否合法
判断猜测结果
记录历史猜测数据并显示
判断猜测次数,如果满6次但是未猜对则判负
如果4个数字全中,则判胜
实现IRandomIntGenerator
实现IGameHistory
将所有连接起来(
显示猜测纪录
)
我们已经完成了大部分工作,各个功能模块(类)都已经搭建出来,最后一步就是将他们连接起来形成完整的程序。