Поделиться через


День в жизни разработчика devops: написание нового кода для истории пользователя

Azure DevOps Services | Azure DevOps Server 2022 — Azure DevOps Server 2019

Visual Studio 2019 | Visual Studio 2022

В этом руководстве описывается, как вы и ваша команда могут получить максимальную выгоду от последних версий Team Foundation Version Control (TFVC) и Visual Studio для создания приложения. В этом руководстве приведены примеры использования Visual Studio и TFVC для извлечения и обновления кода, приостановки работы при прерывании работы, запроса проверки кода, проверки изменений и выполнения других задач.

Когда команда принимает Visual Studio и TFVC для управления кодом, они настраивают свои серверные и клиентские компьютеры, создают невыполненную работу, планируют итерацию и завершают другие действия, необходимые для начала разработки приложения.

Разработчики просматривают невыполненные работы, чтобы выбрать задачи для работы. Они пишут модульные тесты для кода, который они планируют разрабатывать. Как правило, они выполняют тесты несколько раз в час, постепенно пишут более подробные тесты, а затем записывают код, который делает их пройденным. Разработчики часто обсуждают свои интерфейсы кода с коллегами, которые будут использовать метод, который они пишут.

Средства Visual Studio My Work и Code Review помогают разработчикам управлять работой и сотрудничать с коллегами.

Примечание.

Функции Моя работа и Проверка кода в Visual Studio доступны в следующих выпусках:

  • Visual Studio 2022: Visual Studio Community, Visual Studio Professional и Visual Studio Enterprise
  • Visual Studio 2019: Visual Studio Professional и Visual Studio Enterprise

Просмотр рабочих элементов и подготовка к началу работы

Команда согласилась с тем, что во время текущего спринта вы будете работать над оценкой статуса счета, высокоприоритетным элементом в невыполненной работе продукта. Вы решили начать с Реализация математических функций, дочерняя задача элемента невыполненной работы верхнего приоритета.

В Visual Studio Team Explorerна странице "Моя работа" перетащите эту задачу из списка доступных рабочих элементов в список " Работа по ходу выполнения".

Просмотр невыполненной работы и подготовка задач для начала работы

снимок экрана страницы

  1. В Team Explorer, если вы еще не подключены к проекту, в котором вы хотите работать, подключитесь к проекту.

  2. На домашней странице выберите "Моя работа".

  3. На странице "Моя работа" перетащите задачу из списка доступных рабочих элементов в раздел "Работа по ходу выполнения".

    Вы также можете выбрать задачу в списке Доступные рабочие элементы, а затем выбрать Запустить.

Проект добавочного плана работы

Вы разрабатываете код в ряде небольших шагов. Каждый шаг обычно занимает не более часа и может занять не более 10 минут. На каждом шаге вы напишете новый модульный тест и измените код, который вы разрабатываете, чтобы он прошел новый тест, помимо уже написанных тестов. Иногда вы пишете новый тест перед изменением кода, а иногда изменяете код перед написанием теста. Иногда вы выполняете рефакторинг. То есть вы просто улучшаете код, не добавляя новые тесты. Вы никогда не изменяете тест, который успешно проходит, если не решите, что он не соответствует требованиям.

В конце каждого небольшого шага выполняются все модульные тесты, относящиеся к этой области кода. Вы не считаете шаг выполненным, пока все тесты не пройдут.

Вы не выполняете проверку кода на сервер Azure DevOps Server, пока не завершите всю задачу.

Вы можете записать грубый план для этой последовательности небольших шагов. Вы знаете, что точные сведения и порядок последующих этапов, вероятно, изменятся по мере работы. Ниже приведен начальный список шагов для этой конкретной задачи:

  1. Создайте тестовую заглушку метода — только его сигнатуру.
  2. Удовлетворить один конкретный типичный случай.
  3. Проверьте широкий диапазон. Убедитесь, что код правильно реагирует на большой диапазон значений.
  4. Исключение при отрицательном значении. Элегантно справься с некорректными параметрами.
  5. покрытия кода. Убедитесь, что по крайней мере 80% кода выполняется модульными тестами.

Некоторые разработчики пишут этот план в комментариях в своем тестовом коде. Другие просто запоминают свой план. Полезно записать список шагов в поле "Описание" рабочего элемента задачи. Если вы должны временно переключиться на более срочные задачи, вы знаете, где найти список, когда вы сможете вернуться к нему.

Создание первого модульного теста

Начните с создания модульного теста. Начните с модульного теста, так как вы хотите написать пример кода, использующего новый класс.

Это первый модульный тест для библиотеки классов, которую вы тестируете, поэтому вы создадите проект модульного теста.

  1. Выберите Файл>Создать проект.
  2. В диалоговом окне Создание нового проекта щелкните стрелку рядом с Все языки и выберите C#, щелкните стрелку рядом с Все типы проектов и выберите Тест, а затем выберите тестовый проект MSTest.
  3. Выберите Далее, а затем выберите Создать.

снимок экрана с модульным тестом, выбранным в диалоговом окне

В редакторе кода замените содержимое UnitTest1.cs следующим кодом. На этом этапе вы просто хотите проиллюстрировать, как будет вызываться один из новых методов:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Fabrikam.Math.UnitTest
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        // Demonstrates how to call the method.
        public void SignatureTest()
        {
            // Create an instance:
            var math = new Fabrikam.Math.LocalMath();

            // Get a value to calculate:
            double input = 0.0;

            // Call the method:
            double actualResult = math.SquareRoot(input);

            // Use the result:
            Assert.AreEqual(0.0, actualResult);
        }
    }
}

Вы пишете пример в методе тестирования, так как к тому времени, когда вы напишете код, вы хотите, чтобы пример работал.

Создание проекта модульного теста и методов

Обычно вы создаете новый тестовый проект для каждого тестируемого проекта. Если тестовый проект уже существует, можно просто добавить новые методы и классы тестов.

В этом руководстве используется платформа модульного тестирования Visual Studio, но вы также можете использовать платформы из других поставщиков. Обозреватель тестов работает одинаково хорошо с другими платформами, при условии, что вы устанавливаете соответствующий адаптер.

  1. Создайте тестовый проект с помощью предыдущих шагов. Вы можете выбрать такие языки, как C#, F#и Visual Basic.

  2. Добавьте тесты в предоставленный тестовый класс. Каждый модульный тест — один метод.

    • Каждый модульный тест должен быть префиксирован атрибутом TestMethod, а метод модульного теста не должен иметь параметров. Вы можете использовать любое имя, которое требуется для метода модульного теста:

      [TestMethod]
      public void SignatureTest()
      {...}
      
      <TestMethod()>
      Public Sub SignatureTest()
      ...
      End Sub
      
    • Каждый метод теста должен вызывать метод класса Assert, чтобы указать, прошел ли он или завершился сбоем. Как правило, убедитесь, что ожидаемые и фактические результаты операции равны:

      Assert.AreEqual(expectedResult, actualResult);
      
      Assert.AreEqual(expectedResult, actualResult)
      
    • Методы тестирования могут вызывать другие обычные методы, которые не имеют атрибута TestMethod.

    • Можно распределить тесты более чем в один класс. Каждый класс должен быть префиксирован атрибутом TestClass.

      [TestClass]
      public class UnitTest1
      { ... }
      
      <TestClass()>
      Public Class UnitTest1
      ...
      End Class
      

Сведения о написании модульных тестов в C++см. в написании модульных тестов для C/C++ с помощью Microsoft Unit Testing Framework для C++.

Создайте заглушку для нового кода

Затем создайте проект библиотеки классов для нового кода. Теперь существует проект для кода, который находится в процессе разработки, и проект для модульных тестов. Добавьте ссылку на проект из тестового проекта в код, находящийся в разработке.

снимок экрана обозревателя решений с проектами тестов и классов.

В новом проекте вы добавите новый класс и минимальную версию метода, которая, по крайней мере, позволит тесту успешно выполнить сборку. Самый быстрый способ сделать это — создать заглушку класса и метода из вызова в тесте.

public double SquareRoot(double p)
{
    throw new NotImplementedException();
}

Создание классов и методов из тестов

Сначала создайте проект, в котором нужно добавить новый класс, если он еще не существует.

Создание класса

  1. Наведите курсор на пример класса, который вы хотите создать, например, LocalMath, и выберите Быстрые действия и Рефакторинги.
  2. В контекстном меню выберите Создать новый тип.
  3. В диалоговом окне Создания типа установите для Project значение "проект библиотеки классов". В этом примере Fabrikam.Math.

Создание метода

  1. Поместите курсор на вызов метода, например, SquareRoot, и выберите Быстрые действия и рефакторинг.
  2. В контекстном меню выберите Создать метод 'SquareRoot'.

Запуск первого теста

Выполните сборку и запуск теста. Результат теста показывает красный индикатор Сбой, и тест отображается в списке Сбои Тестов.

снимок экрана обозревателя тестов с одним неудачным тестом.

Внесите простое изменение в код:

public double SquareRoot(double p)
{
    return 0.0;
}

Запустите тест еще раз, и он проходит.

снимок экрана Unit Test Explorer с одним успешно пройденным тестом.

Выполнение модульных тестов

Чтобы запустить модульные тесты, выполните следующую команду:

  • Выберите Тест>Запустите все тесты
  • Или, если обозревателя тестов открыт, выберите запустить или запустить все тесты в режимепросмотра.

снимок экрана обозревателя тестов с кнопкой

Если тест отображается в разделе Неудачные тесты, откройте тест, например дважды щелкнув имя. Точка, в которой произошел сбой теста, отображается в редакторе кода.

  • Чтобы просмотреть полный список тестов, выберите Показать все.

  • Чтобы просмотреть сведения о результатах теста, выберите тест в обозревателе тестов.

  • Чтобы перейти к коду теста, дважды щелкните тест в обозревателе тестовили выберите Открыть тест в контекстном меню.

  • Чтобы выполнить отладку теста, откройте контекстное меню для одного или нескольких тестов, а затем выберите Отладка.

  • Чтобы выполнять тесты в фоновом режиме при создании решения, выберите стрелку рядом со значком Параметры, а затем выберите Запуск тестов после сборки. Тесты, которые ранее завершилися сбоем, выполняются сначала.

Согласитесь с интерфейсом

Вы можете сотрудничать с коллегами, которые будут использовать ваш компонент, предоставляя общий доступ к экрану. Коллега может заметить, что многие функции сдадут предыдущий тест. Объясните, что этот тест был просто, чтобы убедиться, что имя и параметры функции правильны, и теперь можно написать тест, который фиксирует основное требование этой функции.

Вы совместно работаете с коллегами, чтобы написать следующий тест:

[TestMethod]
public void QuickNonZero()
{
    // Create an instance to test:
    LocalMath math = new LocalMath();

    // Create a test input and expected value:
    var expectedResult = 4.0;
    var inputValue = expectedResult * expectedResult;

    // Run the method:
    var actualResult = math.SquareRoot(inputValue);

    // Validate the result:
    var allowableError = expectedResult/1e6;
    Assert.AreEqual(expectedResult, actualResult, allowableError,
        "{0} is not within {1} of {2}", actualResult, allowableError, expectedResult);
}

Подсказка

Для этой функции вы используете сначала тестироватьразработки, в которой сначала написать модульный тест для функции, а затем написать код, удовлетворяющий тесту. В других случаях эта практика не реалистична, поэтому вы пишете тесты после написания кода. Но очень важно писать модульные тесты, будь то до или после кода, так как они сохраняют стабильность кода.

Красный, зеленый, рефакторинг...

Следуйте циклу, в котором вы неоднократно пишете тест и подтверждаете, что он завершается ошибкой, напишите код, чтобы пройти тест, а затем рассмотрите возможность рефакторинга, что улучшает код, не изменяя тесты.

Красный

Выполните все тесты, включая созданный тест. После написания каждого теста всегда запускайте его, чтобы убедиться, что он не проходит, прежде чем писать код, который позволяет ему пройти. Скажем, если вы забыли добавить утверждения в некоторые тесты, которые вы создаёте, видя результат Fail, это вселяет уверенность, что при успешном прохождении результат теста правильно показывает, что требование выполнено.

Еще одна полезная практика заключается в настройке выполнения тестов после сборки. Этот параметр выполняет тесты в фоновом режиме при каждом создании решения, чтобы иметь постоянный отчет о состоянии теста кода. Возможно, вы обеспокоены тем, что эта практика может замедлить реагирование Visual Studio, но это редко происходит.

снимок экрана обозревателя тестов с одним проваленным тестом.

Зеленый

Записывает первую попытку кода метода, который вы разрабатываете:

public class LocalMath
{
    public double SquareRoot(double x)
    {
        double estimate = x;
        double previousEstimate = -x;
        while (System.Math.Abs(estimate - previousEstimate) > estimate / 1000)
        {
            previousEstimate = estimate;
            estimate = (estimate * estimate - x) / (2 * estimate);
        }
        return estimate;
    }

Снова запустите тесты, и все они проходят.

снимок экрана обозревателя модульных тестов с двумя пройденными тестами.

Рефакторинг

Теперь, когда код выполняет свою основную функцию, просмотрите код, чтобы найти способы ее улучшения или упростить изменение в будущем. Вы можете уменьшить количество вычислений, выполняемых в цикле:

public class LocalMath
{
    public double SquareRoot(double x)
    {
        double estimate = x;
        double previousEstimate = -x;
        while (System.Math.Abs(estimate - previousEstimate) > estimate / 1000)
        {
            previousEstimate = estimate; 
            estimate = (estimate + x / estimate) / 2;
            //was: estimate = (estimate * estimate - x) / (2 * estimate);
        }
        return estimate;
    }

Убедитесь, что тесты по-прежнему проходят.

Советы

  • Каждое изменение, внесенные при разработке кода, должно быть рефакторингом или расширением:

    • Рефакторинг означает, что вы не изменяете тесты, так как вы не добавляете новые функции.
    • Расширение означает добавление тестов и внесение изменений в код, необходимых для успешного прохождения как существующих, так и новых тестов.
  • Если вы обновляете существующий код до измененных требований, вы также удалите старые тесты, которые больше не представляют текущие требования.

  • Избегайте изменения тестов, которые уже прошли. Вместо этого добавьте новые тесты. Напишите только тесты, представляющие реальное требование.

  • Запустите тесты после каждого изменения.

... и повторите

Продолжайте ряд шагов расширения и рефакторинга, используя список небольших шагов в качестве грубого руководства. Вы не всегда выполняете шаг рефакторинга после каждого расширения, и иногда выполняется несколько этапов рефакторинга в последовательности. Но после каждого изменения кода всегда выполняются модульные тесты.

Иногда вы добавляете тест, который не требует изменений в коде, но это добавляет к уверенности в правильности работы кода. Например, необходимо убедиться, что функция работает в широком диапазоне входных данных. Вы напишете дополнительные тесты, такие как этот:

[TestMethod]
public void SqRtValueRange()
{
    LocalMath math = new LocalMath();
    for (double expectedResult = 1e-8;
        expectedResult < 1e+8;
        expectedResult = expectedResult * 3.2)
    {
        VerifyOneRootValue(math, expectedResult);
    }
}
private void VerifyOneRootValue(LocalMath math, double expectedResult)
{
    double input = expectedResult * expectedResult;
    double actualResult = math.SquareRoot(input);
    Assert.AreEqual(expectedResult, actualResult, expectedResult / 1e6);
}

Этот тест проходит при первом запуске.

снимок экрана обозревателя тестов с тремя пройденными тестами.

Чтобы убедиться, что этот результат не является ошибкой, вы можете временно ввести небольшую ошибку в ваш тест, чтобы он провалился. После того как вы обнаружите сбой, его можно исправить снова.

Подсказка

Всегда завершайте тест сбоем, прежде чем пройти его.

Исключения

Теперь перейдите к написанию тестов для исключительных входных данных:

[TestMethod]
public void RootTestNegativeInput()
{
    LocalMath math = new LocalMath();
    try
    {
        math.SquareRoot(-10.0);
    }
    catch (ArgumentOutOfRangeException)
    {
        return;
    }
    catch
    {
        Assert.Fail("Wrong exception on negative input");
        return;
    }
    Assert.Fail("No exception on negative input");
}

Этот тест помещает код в цикл. Необходимо использовать кнопку Отмена в Обозревателе Тестов. Это завершает код в течение 10 секунд.

Вы хотите убедиться, что бесконечный цикл не может произойти на сервере сборки. Несмотря на то, что сервер устанавливает таймаут для полного выполнения, этот таймаут очень длительный и может привести к значительной задержке. Поэтому в этот тест можно добавить явное время ожидания:

[TestMethod, Timeout(1000)]
public void RootTestNegativeInput()
{...

Явное время ожидания приводит к сбою теста.

Обновите код, чтобы справиться с этим исключительным случаем:

public double SquareRoot(double x)
{
    if (x <= 0.0) 
    {
        throw new ArgumentOutOfRangeException();
    }

Регрессия

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

снимок экрана: сбой модульного теста, который ранее прошел.

Найдите и исправьте ошибку:

public double SquareRoot(double x)
{
    if (x < 0.0)  // not <=
    {
        throw new ArgumentOutOfRangeException();
    }

После исправления все тесты проходят:

снимок экрана обозревателя тестов с четырьмя пройденными тестами.

Подсказка

Убедитесь, что все тесты проходят после каждого изменения, которое вы вносите в код.

Покрытие кода

Через интервалы во время работы и, наконец, перед проверкой кода получите отчет о охвате кода. В этом примере показано, сколько кода было выполнено тестами.

Ваша команда стремится к охвату по крайней мере 80%. Они ослабляют это требование для созданного кода, так как это может быть трудно достичь высокого охвата для этого типа кода.

Хорошее покрытие не гарантирует, что все функциональные возможности компонента проверены, и он не гарантирует, что код будет работать для каждого диапазона входных значений. Тем не менее, существует довольно тесная корреляция между охватом строк кода и охватом поведенческого пространства компонента. Поэтому хорошее покрытие укрепляет уверенность команды в том, что они тестируют большую часть поведения, как и должны.

Чтобы получить отчет о охвате кода, в меню теста Visual Studio выберите Анализ покрытия кода для всех тестов. Все тесты выполняются снова.

Снимок экрана результата покрытия кода и кнопки

При расширении итога в отчете видно, что разрабатываемый код имеет полное покрытие. Это очень удовлетворительно, так как важна оценка для тестируемого кода. Выявленные разделы на самом деле находятся в самих тестах.

Нажав на кнопку Показ покрытия кода цветом, можно увидеть, какие части тестового кода не были выполнены. Код, который не использовался в тестах, выделен оранжевым цветом. Однако эти разделы не имеют значения для покрытия, так как они находятся в тестовом коде и будут использоваться только в том случае, если обнаружена ошибка.

Чтобы убедиться, что определенный тест охватывает определенные ветви кода, можно задать Показать цветовую схему покрытия кода, а затем запустить отдельный тест с помощью команды Запуск в его контекстном меню.

Когда вы закончите?

Вы продолжаете обновлять код маленькими шагами, пока не будете удовлетворены прогрессом.

  • Все доступные модульные тесты успешно проходят.

    В проекте с очень большим набором модульных тестов для разработчика может быть непрактично ожидать их выполнения. Вместо этого, проект осуществляет работу службы гейтед чек-ин, в которой все автоматизированные тесты выполняются для каждого проверенного набора изменений перед объединением в исходное дерево. Проверка кода отклоняется, если выполнение завершается ошибкой. Это позволяет разработчикам выполнять минимальный набор модульных тестов на собственных компьютерах, а затем переходить к другим задачам, без риска сломать сборку. Дополнительные сведения см. в разделе Использование процесса сборки с помощью встроенной сборки для проверки изменений.

  • Покрытие кода соответствует стандарту команды. 75% — это типичное требование проекта.

  • Модульные тесты имитируют каждый аспект требуемого поведения, включая типичные и исключительные входные данные.

  • Код легко понять и расширить.

Когда все эти критерии выполнены, вы готовы проверить код в системе управления версиями.

Принципы разработки кода с помощью модульных тестов

При разработке кода применяются следующие принципы:

  • Разработка модульных тестов вместе с кодом и их частое выполнение во время разработки. Модульные тесты представляют спецификацию компонента.
  • Не изменяйте модульные тесты, если только требования не изменились или тесты не были неправильными. Постепенно добавляйте новые тесты, расширяя функциональные возможности кода.
  • Нацелитесь на не менее 75% кода, которые будут рассмотрены тестами. Просматривайте результаты покрытия кода периодически и перед внесением изменений в исходный код.
  • Добавьте модульные тесты вместе с кодом, чтобы они выполнялись непрерывными или периодическими сборками сервера.
  • Где это возможно, сначала напишите модульный тест для каждой функции. Перед разработкой кода, удовлетворяющего этому коду, выполните это.

Проверка изменений

Перед тем как вносить изменения, снова поделитесь экраном с коллегами, чтобы они могли неофициально и интерактивно просматривать то, что вы создали. Тесты продолжают быть фокусом обсуждения с коллегами, которые в первую очередь заинтересованы в том, что код делает, а не как он работает. Эти коллеги должны согласиться с тем, что написанное вами соответствует их потребностям.

Проверьте все внесенные изменения, включая тесты и код, и свяжите их с выполненными задачами. При регистрации, изменения ставятся в очередь автоматической системой сборки команды для проверки с использованием процесса сборки CI Build команды. Этот процесс построения помогает команде свести к минимуму ошибки в их базе кода, посредством создания и тестирования каждое изменение в чистой среде, отделенной от их рабочих компьютеров.

После завершения сборки вы получите уведомление. В окне результатов сборки вы увидите, что сборка выполнена успешно и все тесты прошли.

Проверка изменений

  1. На странице "Моя работа"Team Explorerвыберите ",.

    снимок экрана: вход из

  2. На странице ожидающие изменения убедитесь, что:

    • Все соответствующие изменения перечислены в разделе «Включенные изменения».
    • Все соответствующие рабочие элементы перечислены в Связанные рабочие элементы.
  3. Введите комментарий, чтобы помочь вашей команде понять цель этих изменений при просмотре журнала управления версиями измененных файлов и папок.

  4. Выберите проверить.

    снимок экрана: проверка ожидающих изменений.

Непрерывная интеграция кода

Дополнительные сведения о том, как определить процесс непрерывной сборки интеграции, см. в разделе Настройка сборки CI. После настройки этого процесса сборки можно получить уведомление о результатах сборок команды.

снимок экрана страницы

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

Дальнейшие действия