Верните нужный объект

1

Я пытаюсь выполнить упражнение по программированию, но один тест терпит неудачу. Что я сделал не так?

Задача:

Напишите программу, которая управляет заводскими настройками робота.

Когда роботы сошли с завода, у них нет имени.

В первый раз, когда вы загружаете их, генерируется случайное имя, такое как 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 = "";
    }
}
  • 1
    What have i done wrong? Вы вставили свой код с минимумом объяснений, надеясь, что мы сделаем всю работу за вас. На первый взгляд, вы, вероятно, хотели бы иметь статичные Names , если не учитывать общий дизайн класса Robot
  • 0
    Я не ожидаю этого вообще. Я явно пытался завершить программу, но я не понимаю, почему этот тест не проходит.
Показать ещё 3 комментария
Теги:

2 ответа

3
Лучший ответ

Создание Names статических проходит все тесты:

private static List<string> Names = new List<string>();

Ключевое слово Static означает, что элемент создается на уровне класса, а не на объекте.

В вашем случае все роботы разделили бы ссылку на один список имен. Удаление ключевого слова static приведет к созданию списка Names каждого объекта Robot. Если вы хотите отслеживать, сколько раз был создан конструктор Robots, вероятно, у вас должен быть общий список имен, который является общим для всех объектов Robot.

Тестирование завершается неудачно, потому что когда создается второй объект, у него есть новый пустой список имен, который первый класс Робота ничего не знает. Поэтому в вашем случае Names.Any(...) всегда будет возвращать false.

Чтобы более подробно прочитать ссылку msdn выше.

  • 0
    Это вы, я буду изучать ссылку!
  • 0
    Да, но это не сделало бы тест неудачным, если бы случайная генерация была в порядке (очень маловероятно, чтобы оба раза генерировалось одно и то же имя). Таким образом, вы правы, но ОП должен также использовать совет Оливье (который сам по себе, как я уже сказал, позволил бы тестам пройти 99,999% времени).
Показать ещё 2 комментария
2

Ошибка не очевидна. Класс Random инициализируется случайным семенем, созданным с текущего системного времени. Часы, дающие системное время, медленно гадают по сравнению с тактовой частотой процессора. Поэтому вполне возможно, что random событие инициализируется дважды с тем же самым семенем, если new Random() вызывается для ускорения в два раза.

Решение. Объявите случайным как статичное и инициализируйте его только один раз.

public class Robot
{
    private static Random random = new Random();

    ...
}

Теперь random создается только один раз независимо от того, сколько роботов вы создаете.

  • 0
    Допустимая точка, но у него есть «охранное» предложение Names.Any(...) для дублированных имен. Попробуйте запустить модульные тесты локально, я думаю, что проблема с Random не решающая, а тот факт, что каждый объект Robot имеет свой собственный список Names
  • 0
    @IlyaIvanov: Если имена действительно случайные, эта проверка редко будет иметь эффект. Но вы правы, список имен должен быть static . И чтобы быть полностью правильным, тест на уникальность пошел бы в цикл вместо просто if .
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню