C# VS2008单元测试-断言方法退出

C# VS2008单元测试-断言方法退出,c#,visual-studio-2008,unit-testing,exit,C#,Visual Studio 2008,Unit Testing,Exit,我正试图用VS2008的内置单元测试框架和我正在测试的方法编写一个C单元测试,调用Environment.Exit(0)。当我在单元测试中调用此方法时,单元测试被中止。该方法实际上应该调用Exit,我想要一种方法来测试它的执行情况,并测试它使用的退出代码。我该怎么做?我看了一下,但没有看到任何相关的东西 [TestMethod] [DeploymentItem("myprog.exe")] public void MyProgTest() { // Want to ensure this

我正试图用VS2008的内置单元测试框架和我正在测试的方法编写一个C单元测试,调用
Environment.Exit(0)
。当我在单元测试中调用此方法时,单元测试被中止。该方法实际上应该调用
Exit
,我想要一种方法来测试它的执行情况,并测试它使用的退出代码。我该怎么做?我看了一下,但没有看到任何相关的东西

[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);
}
编辑:这是我在测试方法中使用的解决方案,感谢:


您将无法对此进行测试-完全终止应用程序。这意味着使用此代码的任何AppDomain都将被完全卸载,无论是您的生产应用程序还是单元测试框架。

这听起来是一个非常糟糕的主意。Exit(0)显然会按照规定执行,因此您的单元测试会中断

如果你真的想继续测试它,你可以通过启动一个单独的进程并检查返回代码来测试它——看看如何将它包装在中

我想另一种选择是将代码分解并注入一个,或者使用一个模拟对象来验证正确的行为


也许你可以用Typemock Isolator做点什么-我相信这可以让你做到。

你唯一的选择就是用fakie Exit方法模拟环境类。

你需要为环境类创建一个包装,然后在代码中使用包装。对于单元测试,插入包装器的模拟版本。下面的示例使用Rhinomock验证该方法是否使用预期参数调用包装器

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()
}
公共类环境包装器
{
公共虚拟无效退出(整数代码)
{
环境。出口(代码);
}
}
公共类MyClass
{
私有环境包装器环境{get;set;}
公共MyClass():此(null){}
公共MyClass(环境包装器)
{
this.Environment=wrapper??新环境wrapper();
}
公共void MyMethod(int代码)
{
this.Environment.Exit(代码)
}
}
[测试方法]
公共void MyMethodTest()
{
var mockWrapper=MockRepository.GenerateMock();
int expectedCode=5;
Expect(m=>m.Exit(expectedCode));
var myClass=新的myClass(mockWrapper);
myclass.MyMethod(expectedCode);
mockWrapper.verifyallexpections()
}

您可以向方法添加一个参数,以向其传递exit()方法不会退出的伪环境


您可以从应用程序中调用的方法中提取此参数化方法,并对提取的函数进行单元测试。这样,您就不必修改应用程序了。

我唯一想到的是:

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

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

+1关于这里的TypeMock隔离器-这是我知道的唯一一个可以让你截取和模拟任何东西的解决方案。能够模拟静态方法的危险在于你不能很容易地放弃使用它们。实际上,我发现(对于我的代码来说)被迫付出额外的努力来获得静态方法是一件好事,因为除非它们是绝对最好的解决方案,否则我不会使用它们。在我看来,这有助于使用更好的技术进行开发。不利的一面是,当与那些静态方法交互时,如果它们确实有意义(或者框架的构建没有考虑到测试),您就不得不跳出障碍。@tvanfosson-这是一个很好的观点。这就是为什么很多人(包括我自己)在编写可测试代码时尽量避免过度使用静态方法的原因。NET框架类是静态的,这是一个痛苦的测试,开发人员通常不得不求助于编写包装器代码,以使其可测试(根据您的答案)。从ASP.NET Web表单到ASP.NET MVC.+1的演变过程中,您可以看到这一点。很好的例子,如果我不吃晚餐,我会按照这些思路编写代码!您的代码让我想起ASP.NET MVC项目AccountController类中的默认代码——这可能只是一件好事。就我个人而言,我会将public EnvironmentWrapper Environment{get;set;}更改为private set,但除了这个好例子之外。
static void myMethod()
{
    DoEnvironmentExit(0);
}

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