为了确保重构正确。重构之后一定要把所有的CASE在跑一遍,确定所有的都PASS。
To-Do-List:
猜测数字
输入验证
生成答案
输入次数
输出猜测结果
验证搞定了。我们来整整随机数。
分析需求:产品代码需要一个随机生成的答案。(1)不重复。(2)4位(3)数字。
这里有个问题:大家都知道随机数是个概率的问题。因为每次生成的数字都不一样。看看之前Guesser类的代码。
public class Guesser { private const string AnswerNumber = "2975"; public string Guess(string inputNumber) { var aCount = 0; var bCount = 0; for (var index = 0; index < AnswerNumber.Length; index++) { if (AnswerNumber[index]==inputNumber[index]) { aCount++; continue; } if (AnswerNumber.Contains(inputNumber[index].ToString())) { bCount++; } } return string.Format("{0}a{1}b", aCount, bCount); } } |
这里我们如果把private const string AnswerNumber = "2975";改为随机的话,那Guesser类测试的结果是不能确定的。也就是说测试依赖了一些可变的东西。比如:随机数、时间等等。
遇到这种情况应该怎么办呢?一种随机数是给产品代码用,我们可以MOCK另外一种"固定随机数"(但是要满足生成随机数的条件)来给测试用。
还是一样先写测试。
[TestClass] public class AnswerGeneratorTest { [TestMethod] public void should_pass_when_answer_generator_number_is_four_digits_and_fully_digital() { Regex regex = new Regex(@"^\d{4}$"); var answerGenerator = new AnswerGenerator(); var actual = regex.IsMatch(answerGenerator.Generate()); Assert.AreEqual(true, actual); } [TestMethod] public void should_pass_when_answer_generator_number_do_not_repeat() { var answerGenerator = new AnswerGenerator(); var actual = answerGenerator.Generate().Distinct().Count() == 4; Assert.AreEqual(true, actual); } } |
实现AnswerGenerator类让测试通过。
引用cao大一段代码稍加修改
public class AnswerGenerator { public string Generate() { var answerNumber = new StringBuilder(); Enumerable.Range(0, 9) .Select(x => new { v = x, k = Guid.NewGuid().ToString() }) .OrderBy(x => x.k) .Select(x => x.v) .Take(4).ToList() .ForEach(num => answerNumber.Append(num.ToString())); return answerNumber.ToString(); } } |
运行测试。
为了解决测试依赖可变的问题。定义IAnswerGenerator。让两种随机数类继承。
public interface IAnswerGenerator { string Generate(); } [csharp] view plaincopy public class AnswerGenerator : IAnswerGenerator { public string Generate() { var answerNumber = new StringBuilder(); Enumerable.Range(0, 9) .Select(x => new { v = x, k = Guid.NewGuid().ToString() }) .OrderBy(x => x.k) .Select(x => x.v) .Take(4).ToList() .ForEach(num => answerNumber.Append(num.ToString())); return answerNumber.ToString(); } } public class AnswerGeneratorForTest : IAnswerGenerator { public string Generate() { return "2975"; } } |