Я пытаюсь выполнить упражнение по программированию, но один тест терпит неудачу. Что я сделал не так?
Задача:
Напишите программу, которая управляет заводскими настройками робота.
Когда роботы сошли с завода, у них нет имени.
В первый раз, когда вы загружаете их, генерируется случайное имя, такое как RX837 или BC811.
Время от времени нам нужно сбросить робот до заводских настроек, а это значит, что их имя будет стерто. В следующий раз, когда вы спросите, он получит новое имя.
Тесты для программы выглядят так, а те, которые терпят неудачу, - это Different_robots_have_different_names:
public class RobotNameTest
{
private Robot robot;
[SetUp]
public void Setup()
{
robot = new Robot();
}
[Test]
public void Robot_has_a_name()
{
StringAssert.IsMatch(@"[A-Z]{2}\d{3}", robot.Name);
}
[Test]
public void Name_is_the_same_each_time()
{
Assert.That(robot.Name, Is.EqualTo(robot.Name));
}
[Test]
public void Different_robots_have_different_names()
{
var robot2 = new Robot();
Assert.That(robot.Name, Is.Not.EqualTo(robot2.Name));
}
[Test]
public void Can_reset_the_name()
{
var originalName = robot.Name;
robot.Reset();
Assert.That(robot.Name, Is.Not.EqualTo(originalName));
}
}
Мой код выглядит так:
public class Robot
{
private List<string> Names = new List<string>();
private string name { get; set; }
public string Name { get { return this.name; } }
public Robot()
{
CreateName();
}
private void CreateName()
{
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var random = new Random();
StringBuilder sb = new StringBuilder();
sb.Append(
new string(
Enumerable.Repeat(chars, 3)
.Select(x => x[random.Next(x.Length)]).ToArray()
)
);
sb.Append(random.Next(100, 999));
if(Names.Any(word => word.Equals(sb.ToString())))
{
CreateName();
}
else
{
name = sb.ToString();
Names.Add(sb.ToString());
}
}
public void Reset()
{
this.name = "";
}
}
Создание Names
статических проходит все тесты:
private static List<string> Names = new List<string>();
Ключевое слово Static означает, что элемент создается на уровне класса, а не на объекте.
В вашем случае все роботы разделили бы ссылку на один список имен. Удаление ключевого слова static приведет к созданию списка Names
каждого объекта Robot. Если вы хотите отслеживать, сколько раз был создан конструктор Robots, вероятно, у вас должен быть общий список имен, который является общим для всех объектов Robot.
Тестирование завершается неудачно, потому что когда создается второй объект, у него есть новый пустой список имен, который первый класс Робота ничего не знает. Поэтому в вашем случае Names.Any(...)
всегда будет возвращать false.
Чтобы более подробно прочитать ссылку msdn выше.
Ошибка не очевидна. Класс Random
инициализируется случайным семенем, созданным с текущего системного времени. Часы, дающие системное время, медленно гадают по сравнению с тактовой частотой процессора. Поэтому вполне возможно, что random
событие инициализируется дважды с тем же самым семенем, если new Random()
вызывается для ускорения в два раза.
Решение. Объявите случайным как статичное и инициализируйте его только один раз.
public class Robot
{
private static Random random = new Random();
...
}
Теперь random
создается только один раз независимо от того, сколько роботов вы создаете.
Names.Any(...)
для дублированных имен. Попробуйте запустить модульные тесты локально, я думаю, что проблема с Random не решающая, а тот факт, что каждый объект Robot имеет свой собственный список Names
static
. И чтобы быть полностью правильным, тест на уникальность пошел бы в цикл вместо просто if
.
What have i done wrong?
Вы вставили свой код с минимумом объяснений, надеясь, что мы сделаем всю работу за вас. На первый взгляд, вы, вероятно, хотели бы иметь статичныеNames
, если не учитывать общий дизайн класса Robot