Модульные тесты VS2008 - выход из метода утверждения

Я пытаюсь написать модульный тест С# со встроенной структурой модульного тестирования VS 2008, а метод, который я тестирую, вызывает Environment.Exit(0). Когда я вызываю этот метод в своем модульном тесте, мой модульный тест прерывается. Метод действительно должен вызывать Exit, и мне нужен способ проверить, что он делает, а также проверить код выхода, который он использует. Как я могу это сделать? Я просмотрел Microsoft.VisualStudio.TestTools.UnitTesting Namespace, но не увидел ничего подходящего.

[TestMethod]
[DeploymentItem("myprog.exe")]
public void MyProgTest()
{
    // Want to ensure this Exit's with code 0:
    MyProg_Accessor.myMethod();
}

Между тем, вот суть кода, который я хочу протестировать:

static void myMethod()
{
    Environment.Exit(0);
}

Изменить: вот решение, которое я использовал в своем методе тестирования, благодаря РичардОД:

Process proc;

try
{
    proc = Process.Start(path, myArgs);
}
catch (System.ComponentModel.Win32Exception ex)
{
    proc = null;
    Assert.Fail(ex.Message);
}

Assert.IsNotNull(proc);
proc.WaitForExit(10000);
Assert.IsTrue(proc.HasExited);
Assert.AreEqual(code, proc.ExitCode);

person Sarah Vessels    schedule 13.07.2009    source источник


Ответы (6)


Это звучит как невероятно плохая идея. Environment.Exit(0), очевидно, будет работать как предписано, поэтому ваши модульные тесты ломаются.

Если вы действительно хотите протестировать это, вы можете запустить отдельный процесс и проверить код возврата — взгляните на его завершение в Process.Start.

Я предполагаю, что другой вариант — это выделить этот код и внедрить тестового шпиона или использовать фиктивный объект. для проверки правильности поведения.

Возможно, вы можете что-то сделать с помощью Typemock Isolator — я считаю, что это позволяет вам -type-and-overriding-a-static-method.aspx" rel="nofollow noreferrer">моделирование статических методов.

person RichardOD    schedule 13.07.2009
comment
+1 на TypeMock Isolator здесь - это единственное известное мне решение, которое позволяет вам перехватывать и издеваться над чем угодно. - person Pavel Minaev; 14.07.2009
comment
Опасность возможности имитировать статические методы заключается в том, что вы не можете так легко отучить себя от их использования. Я на самом деле считаю, что (для моего кода) необходимость прилагать дополнительные усилия, чтобы иметь статические методы, - это хорошо, поскольку я не буду использовать их, если они не являются абсолютным лучшим решением. Это помогает форсировать разработку с использованием лучших методов, IMO. Недостатком является то, что вы вынуждены прыгать через обручи при взаимодействии с этими статическими методами, когда они действительно имеют смысл (или фреймворк не создан с учетом тестирования). - person tvanfosson; 14.07.2009
comment
@tvanfosson- Это хороший момент. Вот почему многие люди (включая меня) стараются избегать чрезмерного использования статических методов при написании тестируемого кода. Классы .NET framework, которые являются статическими, являются испытанием на боль, и разработчикам часто приходится прибегать к написанию кода-оболочки, чтобы сделать его проверяемым (согласно вашему ответу). Вы можете увидеть это на примере эволюции веб-форм ASP.NET в ASP.NET MVC. - person RichardOD; 14.07.2009

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

public class EnvironmentWrapper
{
    public virtual void Exit( int code )
    {
        Environment.Exit( code );
    }
}


public class MyClass
{
    private EnvironmentWrapper Environment { get; set; }

    public MyClass() : this( null ) { }

    public MyClass( EnvironmentWrapper wrapper )
    {
        this.Environment = wrapper ?? new EnvironmentWrapper();
    }

    public void MyMethod( int code )
    {
        this.Environment.Exit( code )
    }
}


[TestMethod]
public void MyMethodTest()
{
     var mockWrapper = MockRepository.GenerateMock<EnvironmentWrapper>();

     int expectedCode = 5;

     mockWrapper.Expect( m => m.Exit( expectedCode ) );

     var myClass = new MyClass( mockWrapper );

     myclass.MyMethod( expectedCode );

     mockWrapper.VerifyAllExpectations()
}
person tvanfosson    schedule 13.07.2009
comment
+1. Хороший пример, если бы я не обедал, я бы написал что-то в этом роде! Ваш код напоминает мне код по умолчанию в классах AccountController проектов ASP.NET MVC, что может быть только хорошо. Лично я бы изменил public EnvironmentWrapper Environment { get; набор; } в приватный набор, но кроме этого прекрасного примера. - person RichardOD; 14.07.2009

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

person Andrew Hare    schedule 13.07.2009

Единственным вариантом здесь было бы издеваться над классом Environment с помощью фальшивого метода Exit.

person Spencer Ruport    schedule 13.07.2009

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

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

person philant    schedule 13.07.2009

Единственное, что приходит мне на ум, это что-то вроде:

static void myMethod()
{
    DoEnvironmentExit(0);
}

static void DoEnvironentExit(int code)
{
    #if defined TEST_SOLUTION
      SomeMockingFunction(code);
    #else
      Environment.Exit(code);
    #endif
}
person Daniel Daranas    schedule 13.07.2009