Выполнение автоматических приемочных тестов на девопах Azure с использованием Specflow - PullRequest
0 голосов
/ 14 января 2019

Я пытаюсь настроить проект Azure DevOps, который запускает некоторые автоматические приемочные тесты при выполнении сборки.

У меня нет проблем с запуском приемочных тестов на моем локальном компьютере, но кажется, что тесты работают неправильно, когда я выполняю сборку на платформе DevOps. Мои модульные тесты работают, как и ожидалось, но приемочные тесты не работают вообще. Вот полный выходной журнал тестовых сборок: https://pastebin.com/ZCx1RdGp

РЕДАКТИРОВАТЬ: После удаления пакетов Runner и SpecFlow я получаю следующий вывод: https://pastebin.com/tTtKEcX5

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

2019-01-14T12:22:38.9295662Z Profile: Acceptance
2019-01-14T12:22:38.9324097Z starting test run
2019-01-14T12:22:38.9324763Z Discovering target: Default
2019-01-14T12:22:39.0023466Z test run finished
2019-01-14T12:22:39.0025670Z publishing test results
2019-01-14T12:22:39.0026124Z test results published
2019-01-14T12:22:39.0026476Z generating reports
2019-01-14T12:22:39.0026874Z creating 1 report(s)
2019-01-14T12:22:39.0027228Z generate Report ReportTemplate.cshtml
2019-01-14T12:22:40.2872092Z reports generated
2019-01-14T12:22:40.2876384Z Result: tests executed with warnings
2019-01-14T12:22:40.2876686Z   Total: 0
2019-01-14T12:22:40.2876843Z   Succeeded: 0
2019-01-14T12:22:40.2876982Z   Ignored: 0
2019-01-14T12:22:40.2877128Z   Pending: 0
2019-01-14T12:22:40.2877260Z   Skipped: 0
2019-01-14T12:22:40.2877390Z   Failed: 0
2019-01-14T12:22:40.2877504Z

Я включил в свой проект следующие пакеты:

  • Пакет Nunit
  • пакет SpecFlow
  • NUnit3TestAdapater
  • SpecRun.Runner
  • SpecRun.SpecFlow

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

Я действительно надеюсь, что кто-то может указать мне правильное направление, спасибо.

ОБНОВЛЕНИЕ на основании ответа Андреаса Виллиха Я сделал следующие вещи

Реализованы эти пакеты в проекте приемочных испытаний. enter image description here

Я разделил свои тесты на две задачи, одну для модульных тестов, а другую для приемочных испытаний. enter image description here Модульные тесты выполняются на MSTest.TestAdapter по умолчанию и успешно завершаются, как и раньше. enter image description here

Я пытаюсь разрешить приемочный тест на TechTalk.SpecRun.VisualStudio.TestAdapter enter image description here

Мне не удалось создать эту работу. Это дает мне следующий вывод: https://pastebin.com/mAR9HK2r

Я не уверен, что искать в моей тестовой сборке и файле csproj, поэтому мне не удалось выполнить эти шаги.

Ответы [ 2 ]

0 голосов
/ 07 июля 2019

Я опубликую то, что сделал, чтобы результаты теста SpecFlow отображались в области Azure DevOps Builds-> Tests, однако предупреждаю, что это хак гигант .

Я полагаю, что тесты SpecFlow / NUnit предполагается поддерживаются так же, как и обычные тесты NUnit, и я думаю, что это связано с настройкой тестового адаптера, как заявил Андреас Виллих, однако я так и не смог его получить работать на меня, и я не смог найти примеры того, где кто-то заставил это работать через обычную конфигурацию конвейера. SpecFlow + также может иметь способы работы, но я не использую версию «плюс». Если / когда я смогу узнать, как это сделать, я перестану использовать нижеприведенное.

  1. Создайте простой процесс для записи имени теста SpecFlow и значений результата теста на диск в формате CSV. Я сделал это, потому что хотел отделить решения по тестированию функций от любой другой логики, применяемой в этом хакере. Этот процесс должен быть таким же простым, как использование шага ловушки [AfterScenario] для извлечения заголовка сценария и значений результата из Scenario.Context - или везде, где вы можете их получить - и записи их в текстовый файл в формате значений, разделенных запятыми.

  2. Интегрируйте этот процесс регистрации результатов CSV в проект SpecFlow, содержащий тесты, результаты которых вы хотите показывать в DevOps Azure.

CSV должен выглядеть примерно так:

DemoScenario_01 Lorem ipsum dolor sit amet consectetur adipiscing elit, Pass
DemoScenario_02 Sed do eiusmod tempor incididunt ut labore et dolore, Pass
DemoScenario_03 Magna aliqua Ut enim ad minim veniam quis, Pass
DemoScenario_04 Nostrud exercitation ullamco laboris nisi ut aliquip, Pass
DemoScenario_05 Ex ea commodo consequat Duis aute irure dolor in, Pass
DemoScenario_06 Reprehenderit in voluptate velit esse cillum dolore eu, Pass
DemoScenario_07 Fugiat nulla pariatur Excepteur sint occaecat cupidatat, Pass
DemoScenario_08 Non proident sunt in culpa qui officia semper, Pass
DemoScenario_09 Deserunt mollit anim id est laborum arcu semper, Pass
DemoScenario_10 Orci a scelerisque purus semper eget Ornare arcu dui vivamus, Pass
  1. Создайте отдельный простой "фиктивный" проект, содержащий только один класс, имеющий один работающий метод NUnit "test", который ничего не делает, кроме Assert.Pass (). Для этого проекта должны быть установлены пакеты NUnit и NUnit3TestAdapter NuGet.

Класс должен выглядеть примерно так:

    namespace DemoNunit
    {
        public class Tests
        {
            [Test]
            public static void DemoTest005()
            {
                Assert.Pass();
            }
        }
    }
  1. Создайте репозиторий Git-кода AzOv DevOps для решения этого «фиктивного» проекта и отправьте его в репозиторий.

  2. Создайте новый конвейер Azure, сконфигурированный для сборок CI, который будет автоматически запускаться, когда фиксации в «пустом» проекте NUnit помещаются в репозиторий. Сконфигурируйте конвейер, чтобы иметь шаг теста Visual Studio под названием «SpecFlow Tests», который ищет dll, содержащую этот единственный тест NUnit. Назовите этот конвейер в соответствии с вашим проектом «SpecFlow» или функциональностью, которую он тестирует, поскольку этот конвейер на самом деле будет отображать эти результаты в области Builds-> Tests.

  3. В новом отдельном проекте "convert" создайте процесс, который будет читать простой файл результатов CSV-вывода из вашего проекта "SpecFlow" и записывать новый файл .cs поверх существующего в " пустышка », в котором находится тест NUnit.

Единственный метод теста NUnit в проекте «фиктивный» теперь будет заменен несколькими методами, по одному для каждого результата, который был зарегистрирован в CSV. Эти методы будут названы как guids минус любые тире, и префикс с буквой, чтобы сделать их действительными именами методов C #. Цель состоит в том, чтобы иметь неповторяющиеся имена методов. Фактические имена тестовых сценариев SpecFlow будут сохранены в атрибутах NUnit TestCase TestName. Assert.Pass () или Assert.Fail () будут использоваться для соответствующих значений результатов, считанных из файла CSV. Скомпилируйте этот «конвертированный» проект в исполняемый файл.

Я пропустил код для чтения результатов CSV ...

    namespace CreateCsFile
    {
        public static class CsFile
        {
            public static string OpenClass = 
                "using NUnit.Framework;" +
                "namespace DemoNunit" +
                "{" +
                "    public class Tests" +
                "    {";
            public static string CloseClass =
                "    }" +
                "}";
            public static string TestMethod =
                "        [Test, TestCase(TestName = \"UniqueNameAttribute\")]" +
                "        public static void MethodName()" +
                "        {" +
                "            Assert.Result();" +
                "        }";
            public static void LogListOfResults(
                List<Test> resultsList)
            {
                Log.CsharpFile(OpenClass);
                foreach (var result in resultsList)
                {
                    Outcome.IsValid(result.Result);
                    var testMethod =
                        TestMethod.Replace(
                                "UniqueNameAttribute",
                                result.Name).
                            Replace(
                                "Result",
                                result.Result).
                            Replace("MethodName",
                                "a" + Guid.NewGuid().
                                    ToString().
                                    Replace("-",""));
                    Log.CsharpFile(testMethod);
                }
                Log.CsharpFile(CloseClass);
            }

            public static void ConvertCsvResultsToNunitResults()
            {
                LogListOfResults(
                    ParseCsv.ResultsSheet());
            }
        }
    }

Журнал класса ...

namespace CreateCsFile
{
    public class Log
    {
        public static string WasFileRemoved
            = "";
        public static string CsFileToggle
            = "True";
        public static string CsFile
            = "C:\\Projects\\DemoNunit\\Tests.cs";
        public static void CsharpFile(
            string nunitData)
        {
            if (CsFileToggle.ToUpper()
                == "TRUE")
            {
                if (string.IsNullOrEmpty(
                    WasFileRemoved))
                {
                    RemoveExistingCsFile();
                }
                var log = !File.Exists(CsFile) ?
                    new StreamWriter(CsFile) :
                    File.AppendText(CsFile);
                log.WriteLine(nunitData);
                log.Close();
            }
        }

        public static void RemoveExistingCsFile()
        {
            if (CsFileToggle.ToUpper()
                == "TRUE")
            {
                WasFileRemoved = "True";
                try
                {
                    var fileInfo = 
                        new FileInfo(CsFile);
                    fileInfo.Attributes =
                        FileAttributes.Normal;
                    File.Delete(fileInfo.FullName);
                }
                catch
                {
                    throw new Exception(
                        @"Unable to delete existing csharp file...");
                }
            }
        }
    }
}

Гадкий вывод:

namespace DemoNunit{    public class Tests    {
        [Test, TestCase(TestName = "DemoScenario_01 Lorem ipsum dolor sit amet consectetur adipiscing elit")]        public static void aa5f7fd239d6a40878780bc6c81f3a18b()        {            Assert. Pass();        }
        [Test, TestCase(TestName = "DemoScenario_02 Sed do eiusmod tempor incididunt ut labore et dolore")]        public static void aa9882fa95b17499eb9386b20a7ff303d()        {            Assert. Pass();        }
        [Test, TestCase(TestName = "DemoScenario_03 Magna aliqua Ut enim ad minim veniam quis")]        public static void a440c25f8c3c24e92ad90224da56bafda()        {            Assert. Pass();        }
        [Test, TestCase(TestName = "DemoScenario_04 Nostrud exercitation ullamco laboris nisi ut aliquip")]        public static void ab2c3cc6997df4a42b0992128f63358f7()        {            Assert. Pass();        }
        [Test, TestCase(TestName = "DemoScenario_05 Ex ea commodo consequat Duis aute irure dolor in")]        public static void a2c9f744dcd2c42c99cb6e288cf09fc78()        {            Assert. Pass();        }
        [Test, TestCase(TestName = "DemoScenario_06 Reprehenderit in voluptate velit esse cillum dolore eu")]        public static void a294422ae029049f9ac4be6f9bb4529cc()        {            Assert. Pass();        }
        [Test, TestCase(TestName = "DemoScenario_07 Fugiat nulla pariatur Excepteur sint occaecat cupidatat")]        public static void aa2dcdf889ffe4e46b57a73882d6f1a68()        {            Assert. Pass();        }
        [Test, TestCase(TestName = "DemoScenario_08 Non proident sunt in culpa qui officia semper")]        public static void a891c43376a5049f89ad75b70fa0a543f()        {            Assert. Pass();        }
        [Test, TestCase(TestName = "DemoScenario_09 Deserunt mollit anim id est laborum arcu semper")]        public static void aa8da317895214abc966c229c832c162f()        {            Assert. Pass();        }
        [Test, TestCase(TestName = "DemoScenario_10 Orci a scelerisque purus semper eget Ornare arcu dui vivamus")]        public static void aa9accb0c9c1b4918b76bc75ff2f2e835()        {            Assert. Pass();        }
    }}

Теперь выполните следующие действия:

  • выполнить тесты вашего проекта "SpecFlow" через командную строку, используя NUnit консоль TestRunner (она должна быть настроена для удаления CSV вывод в какое-то место, например c: \ Temp)
  • выполните ваш проект "convert", который должен быть настроен для чтения CSV в c: \ Temp и обновите файл .cs в проекте "dummy" везде, где его клонированное репо существует на диске
  • через аргументы командной строки, сделайте git commit и отправьте в репозиторий изменить, что exe "convert" сделал в .cs файл "dummy" проекта

Теперь конвейер Azure будет создавать и отображать результаты тестовых выполнений проекта SpecFlow в виде «Тестов SpecFlow» с использованием имен и результатов, которые он хранит в CSV (у меня также есть некоторые демонстрационные идентификаторы). enter image description here

Есть разные способы настройки; один из способов:

  • поместите ваш проект SpecFlow в репозиторий git и создайте конвейер CI за это
  • добавить набор шагов сборки для выполнения тестов через командную строку
  • добавить шаг для вызова exe-файла "convert", который был помещен в исправлено расположение в окне сборки и обновлен файл «фиктивного» проекта, в котором он размещен на отдельной виртуальной машине в общей папке
  • добавить шаг для добавления последнего обновления проекта "dummy" в git repo

Этот конвейер теперь будет автоматически запускаться при коммитах, переданных в его репо, и процесс автоматически преобразует результаты SpecFlow в результаты NUnit, запускает вторичный конвейер и показывает результаты SpecFlow в области Builds-> Tests той секунды pipleine. Первый конвейер не даст результатов, вы всегда будете смотреть на второй конвейер, чтобы увидеть их.

Для поддержки других / других проектов "SpecFlow" таким образом ... они, вероятно, могли бы совместно использовать часть "convert", но ее необходимо улучшить, чтобы иметь возможность передавать в нее местоположение объекта. CS файл, который он обновлял. Затем вы можете создать отдельные «фиктивные» проекты (и, конечно, связанные репозитории / конвейеры) для каждого «SpecFlow» проекта, для которого вы хотите увидеть результаты таким способом. Я еще не дошел до этого, поскольку сейчас я делаю это только для одного проекта.

0 голосов
/ 15 января 2019

Сначала я бы использовал две отдельные задачи для юнит-тестов и приемочных тестов. Это позволяет использовать для них разные тестовые адаптеры (например, NUnit и SpecFlow + Runner).

Если вы используете SpecFlow для приемочных испытаний, вам нужен пакет SpecFlow. Вам нужно только выбрать, какой тестовый адаптер вы используете. Посмотрите ответ, какой пакет вам нужен, в зависимости от тестового адаптера, который вы хотите использовать: https://stackoverflow.com/a/38990326/3155323

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

Когда вы переключились на NUnit, убедитесь, что в вашем app.config настроен NUnit как unitTestProvider и заново созданы все файлы кода.

В качестве следующего шага я бы открыл тестовую сборку и посмотрел, доступны ли сгенерированные тесты. Если нет, посмотрите на ваш файл csproj, если файлы выделенного кода добавлены в группу Compile-ItemGroup.

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

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