Расширение nUnit в той же сборке, что и тесты

История: nUnit 3. У меня есть тесты со сложным наследованием. Определенный объект создается в пределах SetUp или OneTimeSetUp. Эти методы являются виртуальными. Когда этот объект не закрыт, происходит утечка.

Проблема: объект уничтожается в TearDown или OneTimeTearDown, но они вызываются только при успешном выполнении SetUp или OneTimeSetUp. Поэтому, когда где-то в пределах TearDown или OneTimeTearDown возникает исключение, происходит утечка. Как я уже упоминал, существует несколько уровней наследования, поэтому создание исключений и критических объектов может происходить в разных классах, в разных кадрах стека.

Что я хочу сделать: я хочу, чтобы ITestEventListener реагировала на сбой до завершения инициализации и очищала критический объект.

Что я пробовал: в своей тестовой сборке я создал класс:

namespace My.Whatever.Tests.Web.Util
{
    [Extension(EngineVersion = "3.4")]
    public class NunitEventListener : ITestEventListener
    {
        public void OnTestEvent(string report)
        {
            Debug.WriteLine(report);
        }
    }
}

Затем я попытался запустить тесты через

  • VS (тестовый адаптер nunit 3)
  • консоль nUnit

Кажется, никто не загружает расширение.

Вопрос: что я делаю не так?

Источники информации: https://github.com/nunit/docs/wiki/Event-Listeners , https://github.com/nunit/docs/wiki/Writing-Engine-Extensions


person Mike Makarov    schedule 24.10.2017    source источник


Ответы (1)


Информацию о расположении расширений можно найти по адресу https://github.com/nunit/docs/wiki/Engine-Extensibility#locating-addins, который связан со второй из двух упомянутых вами ссылок.

Расширения не ищутся в вашей тестовой сборке. Мы предусмотрели это в версии 2 для надстроек NUnit как простой способ тестирования расширений, но сделать это для расширений движка немного сложнее. IMO, было бы неплохо, если бы мы могли заставить это работать, но это включает в себя возможность загрузки и выгрузки всех расширений при запуске новых тестовых сборок. Это серьезное внутреннее изменение в нашей службе расширения.

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

В двух случаях расположение расширений происходит более или менее автоматически из-за наличия подстановочных знаков в файле .addins:

  1. Если вы устанавливаете средство запуска консоли с помощью NuGet, все расширения, установленные как пакеты nuget, будут найдены.

  2. Если вы устанавливаете средство запуска консоли с помощью Chocolatey, все расширения, установленные с помощью Chocolatey, будут найдены.

Во всех остальных случаях, боюсь, вам придется редактировать файл .addins вручную.

В конкретном случае адаптера нет файла .addins, и поэтому никакие расширения никогда не загружаются. Теоретически вы можете создать такой файл вручную и заставить ваше расширение загружаться, по крайней мере, если движок установлен в каталоге, к которому у вас есть доступ. Это будет иметь место, если вы используете пакет nuget. Я предлагаю вам сначала поиграть с распознаванием вашего расширения в консоли, прежде чем пытаться это сделать, так как это повлечет за собой дополнительные сложности.

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

Обновление: я только что заметил ваше заявление о том, что TearDown и OneTimeTearDown запускаются только в случае успеха SetUp orOneTimeSetUp`. Это не верное утверждение. Оба вида демонтажа запускаются только в том случае, если соответствующая настройка запущена, независимо от того, успешна она или нет. Конечно, ваши разрывы должны быть написаны с учетом того факта, что соответствующая установка может быть не завершена, что может быть непросто.

person Charlie    schedule 24.10.2017
comment
Спасибо, мистер Пул, я принимаю это как ответ, но, может быть, есть другой способ подписаться на непройденный тест события, как в моем случае? В противном случае пока самое простое, что я вижу, — это использовать АОП или сделать что-то вроде динамического генерирования IL и исправления кода во время выполнения. - person Mike Makarov; 24.10.2017
comment
Смотрите обновление в моем ответе. Если все, что вы хотите сделать, это отметить, что тест не прошел, вы сможете сделать это в одном из разборок. В частности, сделайте это во время последнего прогона демонтажа, который соответствует первому прогону настройки. Я не могу придумать ни одной ситуации, в которой этот демонтаж не был бы запущен. - person Charlie; 25.10.2017
comment
Еще раз привет, мистер Пул, я проверял его несколько раз и столкнулся со следующим сценарием: 1) в моем тесте есть OneTimeSetUp и SetUp. 2) SetUp — это виртуальный метод в базовом классе, переопределенный как пустой; 3) OneTimeSetup создает объект. 4) то, что я вижу в журналах teamcity: ошибка SetUp, указывающая на мой OneTimeSetup, с invalidOperationException в инициализации объекта, а затем ничего о запуске OneTimeTearDown. Мой oneTimeTearDown ожидает этого случая и запустится, если будет вызван (создание журналов). Но это не так. - person Mike Makarov; 07.11.2017
comment
Если ошибка связана с созданием объекта тестовой фиксации, то OneTimeSetUp не будет запущен (независимо от того, что написано в журнале) и, следовательно, OneTimeTearDown не запустится. OTOH, если ошибка находится внутри вашего OneTimeSetUp (например, если вы создаете экземпляр какого-то объекта, который дает сбой), будет запущен OneTimeTearDown. - person Charlie; 08.11.2017
comment
Если эта ошибка не появляется только при запуске TeamCity, вам нужно выйти за пределы TeamCity и фактически выполнить отладку на рабочем столе, чтобы действительно знать, что происходит. - person Charlie; 08.11.2017
comment
Спасибо :) Нашел виновника с помощью ваших подсказок. В одном из классов было неправильное переопределение, и это предотвратило вызов ожидаемого метода OneTimeTearDown. - person Mike Makarov; 09.11.2017