继续我们的TDD,还是先看to-do list

  随机生成答案
  检查输入是否合法 
  判断猜测结果
  记录历史猜测数据并显示 
  判断猜测次数,如果满6次但是未猜对则判负 
  如果4个数字全中,则判胜
  
  实现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 class InputValidator
{
    
public bool Validate(string input)
    {
        
return true;
    }
}
这里我只是简单的返回了true,第一,我现在的任务就是让测试通过,而返回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);
}

public bool Validate(string input)
{
    
string[] numbers = input.Split(new []{' '}, StringSplitOptions.RemoveEmptyEntries);
    
if (numbers.Length > 4)
    {
        
return false;
    }
    
return true;
}
再写一个输入元素少于4个的
[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)
{
    
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 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之间
[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)
{
    
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);
}

写代码通过测试并重构
 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

 TestGameHistory
{
    [Test]
    public void should_get_histories_in_order()
    {
        var history 
= new GameHistory();
        history.Add(
new[] {1234}, "0A0B");
        history.Add(
new[] {2345}, "0A2B");
        history.Add(
new[] {4567}, "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()));
    }
}

 

 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 

 RandomIntGenerator : IRandomIntGenerator
{
    private readonly Random random;

    
public RandomIntGenerator()
    {
        random 
= new Random();
    }

    
#region IRandomIntGenerator Members

    
public int Next()
    {
        
return random.Next(010);
    }

    
#endregion
}

 这里并没有再写测试了,一个原因是这个类比较简单,另一个原因是它的主要逻辑都委托给了标准库,而且Random很难测试。

Todo-list
  随机生成答案
  检查输入是否合法 
  判断猜测结果
  记录历史猜测数据并显示 
  判断猜测次数,如果满6次但是未猜对则判负 
  如果4个数字全中,则判胜
  
  实现IRandomIntGenerator 
  实现IGameHistory
  将所有连接起来(显示猜测纪录

我们已经完成了大部分工作,各个功能模块(类)都已经搭建出来,最后一步就是将他们连接起来形成完整的程序。

相关文章:

  • 2021-10-15
  • 2021-10-12
  • 2021-07-12
  • 2021-07-16
  • 2021-11-24
  • 2021-04-23
  • 2021-07-11
  • 2021-09-14
猜你喜欢
  • 2021-10-25
  • 2021-06-14
  • 2021-09-30
  • 2022-01-25
  • 2021-07-23
  • 2021-10-14
  • 2021-09-24
相关资源
相似解决方案