Модульное тестирование метода, содержащего вызов Environment.Exit () внутри него - PullRequest
0 голосов
/ 02 апреля 2019

У меня есть публичный метод сказать,

public void ErrorEncounter()
{
//Global Error Counter
gblErrorCount++;

//Process tremination
Environment.Exit();
}

Этот метод завершается всякий раз, когда он вызывается. Тем не менее, он обновит Global Error Count , который я предполагаю проверить. Есть ли способ выполнить юнит-тестирование по этому методу?

Я использую NUnit Framework для модульного тестирования.

Ответы [ 2 ]

4 голосов
/ 02 апреля 2019

Этот метод разработан, чтобы его было трудно проверить!

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

Три способа обойти это: 1. Исключить метод 2. Не проверяйте метод 3. Измените метод

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

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

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

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

0 голосов
/ 02 апреля 2019

Этот вопрос содержит ответы, показывающие, как можно проверить Environment.Exit(). Внедрение зависимостей в конструктор

Один из вариантов - преобразовать его в зависимость, внедрив его через интерфейс:

interface ITerminator
{
    void Exit();
}

class RealTerminator
{
    void Exit()=>Environment.Exit();
}

public class MyErrorChecker
{
    ITerminator _terminator;
    public class MyErrorChecker(ITerminator terminator)
    {
        _terminator=terminator;
    }

    public void ErrorEncounter()
    {
        //Global Error Counter
        gblErrorCount++;

        //Process tremination
        _terminator.Exit();
    }
}

В тестовом проекте будет реализован поддельный класс терминатора, которыйустанавливает флаг, если вызывается Exit:

class FakeTerminator:ITerminator
{
    public bool Called{get;private set;}
    public void Exit()
    {
        Called=true;
    }
}

Пересмешка

Другой вариант - смоделировать его путем извлечения вызова виртуального метода, который можно заменитьв фиктивном классе:

public void ErrorEncounter()
{
    //Global Error Counter
    gblErrorCount++;

    //Process tremination
    ForceExit();
}

internal virtual void ForceExit()
{
    Environment.Exit();
}

В тестовом проекте может быть создан фиктивный класс проверки ошибок:

class MockErrorChecker:MyErrorChecker
{
    public bool Called{get;private set;}
    public override void ForceExit()
    {
        Called=true;
    }
}

Внедрение функции

Эта опцияне включен в связанный вопросПередайте exit Action в качестве параметра ErrorEncounter, по умолчанию который будет вызывать Environment.Exit():

    public void ErrorEncounter(Action exitFn=null)
    {
        var doExit=exitFn ?? (()=>Environment.Exit());
        //Global Error Counter
        gblErrorCount++;

        //Process tremination
        doExit();
    }

. Тест может передать свою собственную функцию, которая устанавливает флаг:

[Test]
public void Test_Exit_Is_Called
{
    bool called;
    void fakeExit() { called=true; }

    thatClass.ErrorEncounter(fakeExit);

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