Как использовать тесты одобрения Teamcity?

Я использую Тесты одобрения. На моей машине dev я доволен тем, что DiffReporter запускает TortoiseDiff, когда мои результаты теста отличаются от утвержденных:

    [UseReporter(typeof (DiffReporter))]
    public class MyApprovalTests
    { ... }

Однако, когда те же тесты выполняются на Teamcity, а результаты разные тесты терпят неудачу со следующей ошибкой:

System.Exception : Unable to launch: tortoisemerge.exe with arguments ...
Error Message: The system cannot find the file specified
---- System.ComponentModel.Win32Exception : The system cannot find the file 
                                                                 specified

Очевидно, он не может найти tortoisemerge.exe, и это нормально, потому что он не установлен на агенте сборки. Но что, если он будет установлен? Затем для каждого отказа запускается другой экземпляр tortoisemerge.exe, и никто его не закрывает. В конце концов, количество экземпляров tortoisemerge.exe убьет наши серверы:)

Итак, вопрос в том, как должны быть оформлены тесты для запуска Tortoise Diff на локальной машине и просто сообщать об ошибках на сервере сборки? Я знаю #IF DEBUG [UseReporter(typeof (DiffReporter))], но предпочитаю другое решение, если это возможно.

Ответ 1

Есть несколько вариантов решения проблемы Репортеров и CI. Я перечислил их все, а затем укажу на лучшее решение, которое пока еще не реализовано.

  • Используйте AppConfigReporter. Это позволяет вам установить репортер в AppConfig, и вы можете использовать QuietReporter для CI. Здесь есть видео, а также многие другие репортеры. AppConfigReporter появляется в 6:00. Это имеет преимущество отдельных конфигураций, и вы можете украшать на уровне сборки, но имеет недостаток, если вы переопределяете уровень класса/метода, у вас все еще есть проблема.

  • Создайте собственных (2) репортеров. Стоит отметить, что если вы используете репортера, он будет вызван, независимо от того, работает ли он в среде. IEnvironmentAwareReporter позволяет создавать составные репортеры, но не препятствует прямому обращению к репортеру. Скорее всего, вам понадобятся 2 репортера, которые ничего не делают (например, довольно репортер), но работают только на вашем сервере CI или при вызове TeamCity. Назовут его репортером TeamCity. И один, который является мультирепортером, который вызывает команду teamCity, если он работает, в противном случае откладывает.

  • Используйте FrontLoadedReporter (не совсем готов). Это то, как ApprovedTests в настоящее время использует NCrunch. Он выполняет вышеуказанный метод перед тем, что загружается в ваш атрибут UseReporter. Я хотел бы добавить атрибут уровня сборки для его настройки, но еще нет (извините), я постараюсь добавить это очень скоро.

Надеюсь, это поможет. Llewellyn

Ответ 2

Недавно я сам вошел в эту проблему.

Заимствование из xunit и то, как они работают с протоколированием TeamCity, я придумал TeamCity Reporter на основе репортера NCrunch.

public class TeamCityReporter : IEnvironmentAwareReporter, IApprovalFailureReporter
{
    public static readonly TeamCityReporter INSTANCE = new TeamCityReporter();

    public void Report(string approved, string received) { }

    public bool IsWorkingInThisEnvironment(string forFile)
    {
        return Environment.GetEnvironmentVariable("TEAMCITY_PROJECT_NAME") != null;
    }
}

И поэтому я мог бы объединить его с репортером NCrunch:

public class TeamCityOrNCrunchReporter : FirstWorkingReporter
{
    public static readonly TeamCityOrNCrunchReporter INSTANCE = 
        new TeamCityOrNCrunchReporter();

    public TeamCityOrNCrunchReporter()
        : base(NCrunchReporter.INSTANCE,
        TeamCityReporter.INSTANCE) { }
}

[assembly: FrontLoadedReporter(typeof(TeamCityOrNCrunchReporter))]

Ответ 3

Я только придумал одну маленькую идею.

Вы можете реализовать своего собственного репортера, позвоните ему DebugReporter

public class DebugReporter<T> : IEnvironmentAwareReporter where T : IApprovalFailureReporter, new()
{
    private readonly T _reporter;

    public static readonly DebugReporter<T> INSTANCE = new DebugReporter<T>();

    public DebugReporter()
    {
        _reporter = new T();
    }

    public void Report(string approved, string received)
    {
        if (IsWorkingInThisEnvironment())
        {
            _reporter.Report(approved, received);
        }
    }

    public bool IsWorkingInThisEnvironment()
    {
#if DEBUG
        return true;
#else
        return false;
#endif
    }
}

Пример использования,

[UseReporter(typeof(DebugReporter<FileLauncherReporter>))]
public class SomeTests
{
    [Test]
    public void test()
    {
        Approvals.Verify("Hello");
    }
}

Если тест фальсифицирован, он все равно будет красным - но репортер не подошел бы.

IEnvironmentAwareReporter специально определен для этого, но, к сожалению, все, что я туда вернусь, все равно вызывает метод Report(). Итак, я помещаю вызов IsWorkingInThisEnvironment() внутри, что немного хакерское, но работает:)

Надеюсь, что Llywelyn может объяснить, почему он действует так. (Ошибка?)

Ответ 4

Я использую CC.NET, и у меня есть TortoiseSVN, установленный на сервере.

Я переконфигурировал свой сервер сборки, чтобы позволить службе CC.NET взаимодействовать с рабочим столом. Когда я это сделал, TortiseMerge запущен. Поэтому я думаю, что происходит то, что Approvals пытается запустить этот инструмент, но это не так, потому что CC.NET работает как служба, а операционная система предотвращает это поведение по умолчанию. Если TeamCity работает как служба, вы должны быть в порядке, но вы можете протестировать.